【发布时间】:2017-03-17 13:32:03
【问题描述】:
我有一个数据类型,只有在可以对其参数进行排序时才有意义,但是我似乎需要深入研究一些复杂且可能很麻烦的东西才能使其工作(主要是 GADT)。 我正在做的事情(受约束的数据类型)是否被认为是不良的 Haskell 做法,有什么办法可以解决这个问题吗?
有兴趣的可以看看相关代码:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
import Data.List (sort)
data OrdTriple a where
OrdTriple :: (Ord a) => a -> a -> a -> OrdTriple a
instance Functor OrdTriple where
fmap :: (Ord a, Ord b) => (a -> b) -> OrdTriple a -> OrdTriple b
fmap f (OrdTriple n d x) = OrdTriple n' d' x'
where
[n', d', x'] = sort [f n, f d, f x]
起初我以为我只是在 Functor 实例中放置一个上下文(这是我唯一苦苦挣扎的实例),但似乎我不能(没有提及包含的类型),即使我可以我仍然需要对 fmap 的约束,即它的返回类型是可订购的。
事实上,我收到以下编译错误,这似乎是因为我过度约束 Functor 实例:
No instance for (Ord a)
Possible fix:
add (Ord a) to the context of
the type signature for
fmap :: (a -> b) -> OrdTriple a -> OrdTriple b
When checking that:
forall a b.
(Ord a, Ord b) =>
(a -> b) -> OrdTriple a -> OrdTriple b
is more polymorphic than:
forall a b. (a -> b) -> OrdTriple a -> OrdTriple b
When checking that instance signature for ‘fmap’
is more general than its signature in the class
Instance sig: forall a b.
(Ord a, Ord b) =>
(a -> b) -> OrdTriple a -> OrdTriple b
Class sig: forall a b. (a -> b) -> OrdTriple a -> OrdTriple b
In the instance declaration for ‘Functor OrdTriple’
【问题讨论】:
-
Functor 必须适用于所有类型,而不仅仅是那些受
Ord约束的类型。即使在您的实例中,您也无法进一步限制它。这就是为什么像平衡树这样的结构也不能成为函子的原因。 -
你不能把它变成函子。通常的解决方法是简单地实现一个单独的“map”函数,就像
Data.Set和Data.Map所做的那样。
标签: haskell type-constraints gadt