Haskell 高阶函数中的多态性?
我有一个代数数据类型,其中一些构造函数具有可比较的值,而一些构造函数不具有可比较的值。我编写了一些比较函数,它们的工作方式类似于标准的Haskell 高阶函数中的多态性?,haskell,types,polymorphism,higher-order-functions,Haskell,Types,Polymorphism,Higher Order Functions,我有一个代数数据类型,其中一些构造函数具有可比较的值,而一些构造函数不具有可比较的值。我编写了一些比较函数,它们的工作方式类似于标准的(==)和(/=)运算符,但对于没有意义的比较,它们返回Nothing: data Variant = IntValue Int | FloatValue Float | NoValue equal :: Variant -> Variant -> Maybe Bool equal (IntValu
(==)
和(/=)
运算符,但对于没有意义的比较,它们返回Nothing
:
data Variant = IntValue Int
| FloatValue Float
| NoValue
equal :: Variant -> Variant -> Maybe Bool
equal (IntValue a) (IntValue b) = Just (a == b)
equal (FloatValue a) (FloatValue b) = Just (a == b)
equal _ _ = Nothing
unequal :: Variant -> Variant -> Maybe Bool
unequal (IntValue a) (IntValue b) = Just (a /= b)
unequal (FloatValue a) (FloatValue b) = Just (a /= b)
unequal _ _ = Nothing
这是可行的,但是重复是不方便的——特别是因为我实际上有更多的Variant
构造函数和更多的比较函数
我想我可以将重复分解成一个辅助函数,该函数在比较函数中参数化:
helper :: (Eq a) => (a -> a -> Bool) -> Variant -> Variant -> Maybe Bool
helper f (IntValue a) (IntValue b) = Just (f a b)
helper f (FloatValue a) (FloatValue b) = Just (f a b)
helper _ _ _ = Nothing
equal' :: Variant -> Variant -> Maybe Bool
equal' = helper (==)
unequal' :: Variant -> Variant -> Maybe Bool
unequal' = helper (/=)
但是这不起作用,因为类型变量a
显然不能在helper
的定义中同时绑定到Int
和Float
;GHC将其绑定到Float
,然后抱怨处理IntValue
的行上的类型不匹配
像
(==)
这样的函数在直接使用时是多态的;是否有方法将其传递给另一个函数并使其保持多态性?是的,这是可能的,但仅限于:
所有a.的都是关于它听起来像什么;a
在括号内普遍量化,在括号外则超出范围。这意味着f
参数必须在属于Eq
实例的所有类型a上具有多态性,这正是您想要的
这里的扩展名为“rank2”,因为它允许在最外层范围内使用常规样式的多态性,以及此处示例中的多态参数。为了进一步嵌套,您需要扩展RankNTypes
,它是相当自描述性的
另一方面,关于更高级别的多态类型——请记住,forall
实际上是将变量绑定到类型的;事实上,你可以认为他们的行为很像羔羊。当您将这样一个函数应用于具有具体类型的对象时,参数的类型将隐式地由该用法的forall
绑定。例如,如果您尝试使用一个值,该值的类型被该函数外部的所有
绑定;值的类型超出了范围,这使得很难做任何合理的事情(正如您可能想象的那样)。Hmm,我感觉答案将涉及所有的,实际上我几乎完全尝试了,但我缺少了您添加的一对括号。我不太明白为什么那些父母是必要的;不要使用它们。@Wyzard:这就是我添加编辑的原因。。。想象一下,forall
实际上是一个函数,它接受了一个额外的参数(有点像是在幕后)。括号是作为helper
(默认值)或f
(您需要的)参数的类型之间的区别。在大括号中写入“类型参数”,在一种情况下,我们有helper{a}(f::a->a->Bool)(IntValue x)(IntValue y)=Just(fxy)
,这是一个类型错误,因为a
在外部范围内(在Int
和Float
的不同位置使用)。在另一个位置,我们有helper f(IntValue x)(IntValue y)=Just(f{Int}xy)
,同样地,将f
应用到另一个位置的Float
,因此类型工作。好的,我想我现在明白了。谢谢
{-# LANGUAGE Rank2Types #-}
helper :: (forall a. (Eq a) => (a -> a -> Bool))
-> Variant -> Variant -> Maybe Bool
helper f (IntValue a) (IntValue b) = Just (f a b)
helper f (FloatValue a) (FloatValue b) = Just (f a b)
helper _ _ _ = Nothing