问题描述
我已经定义了以下数据类型:
I have defined the following data type:
data Probability a = PD { mass :: [(a, Ratio Int)] }
现在我想写出它是一个 Functor的实例
:
Now I want to write that it is an instance of Functor
:
collect :: (Eq a, Num b) => [(a, b)] -> [(a, b)]
collect al = map collect' keys where
keys = nub $ map fst al
collect' k = (k, sum (map snd (matches k)))
matches k = filter ((==) k . fst) al
instance (Eq a) => Functor (Probability a) where
fmap f p = PD (collect $ map (first f) (mass p))
然而,我得到以下错误:
However, I get the following error:
Kind mis-match
The first argument of `Functor' should have kind `* -> *',
but `Probability a' has kind `*'
In the instance declaration for `Functor (Probability a)'
如何添加必要的 Eq a
约束? (我正在使用GHC 7.4.1)
How can I add the necessary Eq a
constraint? (I'm using GHC 7.4.1)
推荐答案
可悲的是,你不能这么做 - Functor
实例必须接受任何类型的映射函数而不受限制。
Sadly, you can't do that—Functor
instances must accept any kind of mapping function without restriction.
尽管如此,您可以假装它。
You can kind of fake it, though.
newtype PF a = PF { unPF :: forall r . Eq r => (a -> r) -> Probability r }
instance Functor PF where
fmap f (PF p) = PF (\mp -> p (mp . f))
这里,映射到 Probability
的所有函数都被延迟由 PF
。在可能的情况下,我们通过降低回到 Probability
中来一次性运行它们。
Here, all of the functions that would be mapped over Probability
have been "deferred" by PF
. We run them all at once by "lowering" back into Probability
when possible
lowerPF :: Eq a => PF a -> Probability a
lowerPF pf = unPF pf id
为了将一个 Probability
转换为 fmappable
PF
,我们必须提升它
And in order to convert a Probability
into a fmappable
PF
we must "lift" it
liftPF :: Probability a -> PF a
liftPF p = PF $ \mp -> PD (collect $ map (first mp) (mass p))
这篇关于如何将类约束添加到Haskell中的Functor实例声明中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!