我来自标准ML,并且是Haskell的新手,所以我仍然试图围绕精心设计的类型系统。我想创建一个模块,公开一个代数数据类型Expression a
以及一些可以与Expression a
类型的值一起使用的函数。仅此一点并不算太糟糕。小警告:我想将a
类型限制在Num
类型类中,以便函数可以将a
值用作数字。还是不太糟糕;经过一番探讨之后,我相信我想用它来称之为“GADT”。
更大的警告:所以在大多数情况下,可以为Num
类型类中的所有类型定义相同的函数。但是,如果a
在Integral
类型类中,我希望一些函数中的一些函数具有一些替代行为,如果a
中有Fractional
,则需要一些替代行为1}}类型类。但是在大多数情况下,所有Num
类型的所有内容都是相同的,所以我不想为一般情况Integral
和Fractional
分别重写所有内容,因为导致大量重复的代码。
据我所知,这称为“Ad hoc多态”,这是Haskell通过类型类系统支持的。但是,由于两个原因,这似乎更复杂:1,这是一个ADT,其构造函数必须在默认函数中使用,也必须在Integral
特定的和Fractional
特定的替代函数中使用。 2,Integral
和Fractional
是类型类(不是类型)所以我不确定这是否会让它更难为它们制定特定的行为。
同样,我是Haskell的新手,所以我可能认为这一切都错了。
编辑以澄清。所有困难归结为:我想为Nums做一个默认行为,然后如果Num碰巧是一个积分则是一个替代行为,如果Num恰好是一个分数,则会有另一个替代行为。
答案 0 :(得分:4)
首先,您想要对a
到Num
的限制做什么并不需要像GADT那样精心设计的任何内容。如果您的类型为Expression a
,函数为exprFunc
,则可以按如下方式声明:
exprFunc :: Num a => Expression a -> Expression a
这样,exprFunc
将只有Num
的参数。至于你的第二个问题,在Haskell中做多态函数的唯一(接受)方法是通过类型类。因此,对于Integral
和Fractional
的示例,最好的方法是执行以下操作。
class Num a => C a where
exprMethod :: Expression a -> Expression a
现在,您可以为exprMethod
和Fractional
定义Integral
的两个单独定义。
instance Fractional a => C a where
exprMethod expr = <some code>
instance Integral a => C a where
exprMethod expr = <some other code>