我的代码看起来有点像以下内容:
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 $ Real 0.0
的ComplexNumber。
问题是如何使Complex Number
成为可能。由于Number
中的所有类型都有相应的Complex
个实例,我可以将deriving Complex
添加到Number
吗?
答案 0 :(得分:3)
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让“用户”决定表达式应该被评估为什么数字类型。
答案 1 :(得分:0)
这似乎不是合法的Haskell代码。您有三个ComplexNum
类型的构造函数,都是Complex
。此外,数据类型必须以大写字母开头,因此foo
不是有效类型。很难说出你的意思,但我会采取刺:
如果您有类型
data Complex a = (a,a)
您可以保留Number
的定义并将foo
定义为:
data Foo = N Number
| C (Complex Number)