我正在玩Data.Fix
和Data.Functor.Sum
,并尝试将cata
与仿函数一起使用,然后遇到一个代码没有打字的问题。但我不确定如何进行类型检查。
这是代码。
{-# LANGUAGE DeriveFunctor, FlexibleInstances, MultiParamTypeClasses #-}
import Data.Fix (Fix(Fix), cata)
import Data.Functor.Sum (Sum(InL, InR))
import Prelude hiding (succ)
class (Functor f, Functor g) => IsPartOf f g where
inj :: f a -> g a
app :: (f a -> a) -> (g a -> a)
instance {-# OVERLAPPABLE #-} Functor f => IsPartOf f f where
inj = id
app = id
instance {-# OVERLAPPABLE #-} (Functor f, Functor g) => IsPartOf f (Sum f g) where
inj = InL
app f (InL l) = f l
instance {-# OVERLAPPABLE #-} (Functor f, Functor g, Functor h, IsPartOf f g) => IsPartOf f (Sum h g) where
inj = InR . inj
app f (InR r) = app f r
data Zero e = Zero deriving Functor
data Succ e = Succ e deriving Functor
data Add e = Add e e deriving Functor
type Expr = Sum Zero (Sum Succ Add)
zero :: Fix Expr
zero = Fix (inj Zero)
succ :: Fix Expr -> Fix Expr
succ = Fix . inj . Succ
add :: Fix Expr -> Fix Expr -> Fix Expr
add = ((Fix . inj) .) . Add
class Value f where
value :: Num a => f a -> a
instance Value Zero where
value _ = 0
instance Value Succ where
value (Succ e) = 1 + e
instance Value Add where
value (Add e1 e2) = e1 + e2
{-
instance (Value f, Value g) => Value (Sum f g) where
value (InL f) = value f
value (InR g) = value g
-}
首先,我有三个仿函数Zero
,Succ
和Add
。我使用Sum
和type Expr = Sum Zero (Sum Succ Add)
定义了它们。
我还有Value
类将每个仿函数转换为数字。由于我不想自己为Value
编写Sum
的实例,因此我介绍了IsPartOf
类,该类知道如何构造一个函子的总和(inj
)以及如何将内部仿函数的函数应用于外部仿函数(app
)。
但是当我尝试像cata (app value) (succ zero)
那样使用它们时,GHC表示它不会进行类型检查。
*Main> cata (app value) (succ zero)
<interactive>:10:7:
Overlapping instances for IsPartOf f0 Expr
arising from a use of ‘app’
Matching instances:
instance [overlappable] (Functor f, Functor g, Functor h,
IsPartOf f g) =>
IsPartOf f (Sum h g)
-- Defined at min.hs:16:31
instance [overlappable] Functor f => IsPartOf f f
-- Defined at min.hs:10:31
instance [overlappable] (Functor f, Functor g) =>
IsPartOf f (Sum f g)
-- Defined at min.hs:13:31
(The choice depends on the instantiation of ‘f0’
To pick the first instance above, use IncoherentInstances
when compiling the other instance declarations)
In the first argument of ‘cata’, namely ‘(app value)’
In the expression: cata (app value) (succ zero)
In an equation for ‘it’: it = cata (app value) (succ zero)
<interactive>:10:11:
Could not deduce (Value f0) arising from a use of ‘value’
from the context (Num a)
bound by the inferred type of it :: Num a => a
at <interactive>:10:1-28
The type variable ‘f0’ is ambiguous
Note: there are several potential instances:
instance Value Add -- Defined at min.hs:41:10
instance Value Succ -- Defined at min.hs:39:10
instance Value Zero -- Defined at min.hs:37:10
In the first argument of ‘app’, namely ‘value’
In the first argument of ‘cata’, namely ‘(app value)’
In the expression: cata (app value) (succ zero)
为什么GHC找不到合适的实例?如何进行此类型检查,或者表达此想法的正确方法是什么?
我用GHC 7.10.3尝试了这个。