Получение данных. Комплекс в Хаскеле

У меня есть код, который выглядит примерно так:

import Data.Complex

data Foo = N Number
         | C ComplexNum

data Number = Int Integer
            | Real Float
            | Rational Rational
     deriving Show

data ComplexNum = con1 (Complex Integer)
                | con2 (Complex Float)
                | con3 (Complex Rational)
     deriving Show

Но это кажется плохим способом сделать это. Я бы предпочел

data Foo = N Number
         | C (Complex Number)

и построить ComplexNumber с чем-то похожим на ComplexNumber $ Real 0.0,

Вопрос в том, как сделать Complex Number возможный. Поскольку все типы в Number иметь соответствующий Complex случаи, я могу просто добавить deriving Complex в Number?

2 ответа

Подход Haskell состоит в том, чтобы иметь различные типы для Complex Float а также Complex Int вместо того, чтобы пытаться объединить их в один тип. С помощью классов типов вы можете определить все эти типы одновременно:

data Complex a = C a a

instance Num a => Num (Complex a) where
  (C x y) + (C u v) = C (x+u) (y+v)
  (C x y) * (C u v) = C (x*u-y*v) (x*v+y*u)
  fromInteger n = C (fromInteger n) 0
  ...

Это сразу определяет Complex Int, Complex Double, Complex Rationalи т. д. Действительно, это даже определяет Complex (Complex Int),

Обратите внимание, что это не определяет, как добавить Complex Int к Complex Double, Дополнение (+) по-прежнему имеет тип (+) :: a -> a -> a так что вы можете только добавить Complex Int к Complex Int и Complex Double другому Complex Double,

Чтобы добавить числа разных типов, вы должны явно преобразовать их, например:

addIntToComplex :: Int -> Complex Double -> Complex Double
addIntToComplex n z = z + fromIntegral n

Взгляните на http://www.haskell.org/tutorial/numbers.html раздел 10.3 для более полезных функций преобразования между классами числовых типов в Haskell.

Обновить:

В ответ на ваши комментарии я бы предложил больше сосредоточиться на операциях, а не на типах.

Например, рассмотрим это определение:

onethird = 1 / 3

Это представляет общее значение "1/3" во всех классах чисел:

import Data.Ratio

main = do
    putStrLn $ "as a Double: " ++ show (onethird :: Double)
    putStrLn $ "as a Complex Double: " ++ show (onethird :: Complex Double)
    putStrLn $ "as a Ratio Int: " ++ show (onethird :: Ratio Int)
    putStrLn $ "as a Complex (Ratio Int): " ++ show (onethird :: Complex (Ratio Int))
    ...

В некотором смысле, Haskell позволяет "пользователю" решать, какой числовой тип следует использовать для выражения.

Это не является допустимым кодом Haskell. У вас есть три конструктора типа ComplexNum все по имени Complex, Кроме того, типы данных должны начинаться с заглавной буквы, поэтому foo недопустимый тип Трудно сказать, что вы имеете в виду, но я сделаю удар:

Если у вас есть тип

data Complex a = (a,a)

Вы можете сохранить свое определение Number и определить foo как:

data Foo = N Number
         | C (Complex Number)
Другие вопросы по тегам