haskell - 无法从上下文错误中推断出包含的约束
问题描述
我正在努力在 Haskell 中重新创建一些基本的类别理论,但我遇到了一个问题。我的代码看起来像这样——非常标准。当然,这是隐藏 id 和 (.)。
class Category c where
id :: forall a. c a a
(.) :: c b d -> c a b -> c a d
-- Recover usual behavior of . and id
instance Category (->) where
id = \x -> x
(.) = \f g x -> f $ g x
class (Category c, Category d) => Functor c d f where
fmap :: c a b -> d (f a) (f b)
data Comp f g x = Comp {getComp :: f (g x)}
instance (Category c, Category d, Category e,
Functor d e f, Functor c d g) => Functor c e (Comp f g) where
fmap = _
最后一个实例声明抛出了一个非常丑陋的错误,
• Could not deduce (Functor d0 e f)
from the context: (Category c, Category d, Category e,
Functor d e f, Functor c d g)
bound by an instance declaration: ...
type variable d0 is ambiguous.
我已经玩了一段时间了,我不太清楚发生了什么。我对haskell很陌生。
解决方案
让我们尝试修复您的代码
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
import Prelude hiding (Functor, fmap, id, (.))
import Data.Coerce
class Category c where
id :: forall a. c a a
(.) :: c b d -> c a b -> c a d
coerceC :: Coercible a b => c a b
-- Recover usual behavior of . and id
instance Category (->) where
id = \x -> x
(.) = \f g x -> f $ g x
coerceC = coerce
class (Category c, Category d) => Functor c d f where
fmap :: c a b -> d (f a) (f b)
到目前为止,一切都很好。我在 中添加了coerceC
方法Category
,我们很快就会看到原因。(profunctors
包定义.#
和#.
大致相同的目的:http ://hackage.haskell.org/package/profunctors-5.2.2/docs/Data-Profunctor-Unsafe.html#t:Profunctor )
接下来,我们需要写一些具体的东西来获得洞察力。让我们试试[]
函子:
instance Functor (->) (->) [] where
fmap = map
请注意,这[]
是一个 Functor (->) -> (->)
。洞察力是函子确定/“知道”源和目标类别。我们可以通过FunctionalDependencies
.
class (Category c, Category d) => Functor c d f | f -> c d where
fmap :: c a b -> d (f a) (f b)
然后我们可以继续Comp
举例。注意: - 这是newtype
为了coerceC
工作 - 我放弃了Category
约束,因为它们暗示Functor
newtype Comp f g x = Comp {getComp :: f (g x)}
instance (Functor d e f, Functor c d g) => Functor c e (Comp f g) where
fmap = _
现在我们得到一个类型孔错误,我们期待:
Found hole: _ :: c a b -> e (Comp f g a) (Comp f g b)
那就是我们可以填写
instance (Functor d e f, Functor c d g) => Functor c e (Comp f g) where
fmap :: forall a b. c a b -> e (Comp f g a) (Comp f g b)
fmap ab
= coerceC
. (fmap (fmap ab :: d (g a) (g b)) :: e (f (g a)) (f (g b)))
. coerceC
(编写类型中间签名有助于使事情变得正确,在这种情况下,我们至少需要一个,因为coerceC
它是非常多态的)