如何在Haskell中向Functor实例声明添加类约束?

Bol*_*olo 5 haskell functor

我已经定义了以下数据类型:

data Probability a = PD { mass :: [(a, Ratio Int)] } 
Run Code Online (Sandbox Code Playgroud)

现在我想写一下它是一个实例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))
Run Code Online (Sandbox Code Playgroud)

但是,我收到以下错误:

Kind mis-match
The first argument of `Functor' should have kind `* -> *',
but `Probability a' has kind `*'
In the instance declaration for `Functor (Probability a)'
Run Code Online (Sandbox Code Playgroud)

如何添加必要的Eq a约束?(我正在使用GHC 7.4.1)

J. *_*son 9

遗憾的是,你无法做到这一点 - Functor实例必须接受任何类型的映射功能而不受限制.

不过,你可以假装它.

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))
Run Code Online (Sandbox Code Playgroud)

在这里,所有要映射的函数Probability都被"延迟"了PF.我们Probability在可能的情况下通过"降低"来立即运行它们

lowerPF :: Eq a => PF a -> Probability a
lowerPF pf = unPF pf id
Run Code Online (Sandbox Code Playgroud)

并且为了将a转换Probability为a,fmappable PF我们必须"解除"它

liftPF :: Probability a -> PF a
liftPF p = PF $ \mp -> PD (collect $ map (first mp) (mass p))
Run Code Online (Sandbox Code Playgroud)


Dom*_*ese 5

您所写的不是Functor。甲Functorfmap必须支持任意值类型被映射,而不仅仅是那些满足特定的约束。您可以将其作为更一般概念的实例。例如,包“ 约束类别”定义了一类约束函子。