Получение данных. Комплекс в Хаскеле
У меня есть код, который выглядит примерно так:
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)