0

我的代码如下所示:

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 ComplexNumber吗?

4

2 回答 2

4

Haskell 方法是使用不同的类型Complex FloatComplex 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).

请注意,这并未定义如何将 a 添加Complex Int到 a Complex Double。加法 (+) 仍然具有类型(+) :: a -> a -> a,因此您只能将 a 添加Complex Int到 aComplex Int并将 a添加Complex Double到 another 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 让“用户”决定表达式应该被评估为什么数字类型。

于 2014-01-26T05:44:16.483 回答
0

这似乎不是合法的 Haskell 代码。您有三个类型的构造函数,ComplexNum它们都命名为Complex. 此外,数据类型必须以大写字母开头,因此foo不是有效类型。很难说出你的意思,但我会刺一下:

如果你有一个类型

data Complex a = (a,a)

您可以保留您的定义Number并定义foo为:

data Foo = N Number
         | C (Complex Number)
于 2014-01-26T05:40:05.263 回答