我想创建一个复杂类型来表示复数.
以下作品:
Prelude> data Complex = Complex Int Int
Prelude> :t Complex
Complex :: Int -> Int -> Complex
Run Code Online (Sandbox Code Playgroud)
如何更改此接受任何Num类型,而不仅仅是Int.
我试过以下:
Prelude> data Complex a = Num a => Complex a a
Run Code Online (Sandbox Code Playgroud)
但得到了这个:
* Data constructor `Complex' has existential type variables, a context, or a specialised result type
Complex :: forall a. Num a => a -> a -> Complex a
(Use ExistentialQuantification or GADTs to allow this)
* In the definition of data constructor `Complex'
In the data type declaration for `Complex'
Run Code Online (Sandbox Code Playgroud)
我不确定该怎么做这个错误.任何帮助表示赞赏.
lef*_*out 11
传统data的Haskell就是:数据.它不需要知道关于其字段属性的任何信息,只需要能够存储它们.因此,没有必要在那时限制字段; 只是做到了
data Complex a = Complex !a !a
Run Code Online (Sandbox Code Playgroud)
(!因为严格的字段对性能更好).
当然,当您实现Num实例时,您将需要一个约束:
instance (Num a) => Num (Complex a) where
fromInteger = (`Complex`0) . fromInteger
Complex r i + Complex ? ? = Complex (r+?) (i+?)
...
Run Code Online (Sandbox Code Playgroud)
......事实上,你需要更强大的约束RealFloat a来实现abs,至少标准版本是如何实现的.(这意味着,Complex Int实际上是不可用的,不是标准的Num层次结构;你需要例如Complex Double.)
也就是说,也可以将约束烘焙到数据类型本身.您尝试过的ExistentialTypes语法虽然非常有限,但并不适用于此; 你想要的是GADT
data Complex a where
Complex :: Num a => a -> a -> Complex a
Run Code Online (Sandbox Code Playgroud)
有了这个,您就可以实现例如添加而不提及签名中的任何约束
cplxAdd :: Complex a -> Complex a -> Complex a
cplxAdd (Complex r i) (Complex ? ?) = Complex (r+?) (i+?)
Run Code Online (Sandbox Code Playgroud)
现在,您将需要满足Num ,只要你试图建立一个Complex虽然值.这意味着,您仍然需要在Num实例中使用显式约束.
此外,此版本可能要慢得多,因为Num字典实际上需要存储在运行时表示中.