![](/img/trans.png)
[英]Why does this Haskell code typecheck with fundeps but produce an untouchable error with type families?
[英]Haskell: Why does GHC not infer type in this typeclass with fundeps?
我正在尝试使用类型类和函数依赖项来获取一个类型函数 ,可以在下面的代码中将Cont Int
, Int
转换为Cont Int
,然后在另一个类型类中使用它,如下所示。
{-# LANGUAGE KindSignatures, FunctionalDependencies, FlexibleInstances, FlexibleContexts #-}
newtype TestData a b = TestData b
newtype Cont a = Cont a
class TypeConv (repr :: * -> *) a b | repr a -> b where
class Lift repr a where
liftOp :: (TypeConv repr a a') => a -> repr a'
instance TypeConv (TestData a) Int (Cont Int) where
instance Lift (TestData a) Int where
liftOp i = TestData (Cont i)
这是来自ghci 7.4.2的错误
src/Test.hs:13:26:
Could not deduce (a' ~ Cont Int)
from the context (Full (TestData a) Int a')
bound by the type signature for
liftOp :: Full (TestData a) Int a' => Int -> TestData a a'
at src/Test.hs:13:5-32
a' is a rigid type variable bound by
the type signature for
liftOp :: Full (TestData a) Int a' => Int -> TestData a a'
at src/Test.hs:13:5
In the return type of a call of `Cont'
In the first argument of `TestData', namely `(Cont i)'
In the expression: TestData (Cont i)
鉴于TypeConv
类型类有一个fundep我读作:“给定repr
和a
,我们可以推断b
”并为Int
提供了一个实例,为什么ghc不能推断a' ~ Cont Int
?
如果你想要一个类型函数,请使用Type Families - 这就是它们的用途。 家庭类型很容易,做你期望的。
通常编译器不推断您的类型的原因是您指定了函数依赖(逻辑关系)而不是函数(计算工具)。 使用fundeps是出了名的反直觉,部分原因是你在类型级别进行逻辑编程,同时在价值级别进行函数式编程。 开关! 使用类型级别的函数,具有可爱的Type Families扩展。 配有免费的lambda冰箱磁铁,只有四个令牌(不包括p&p)。
我不确定你想要达到的目的,但这里有一个例子 - 如果我朝错误的方向前进,请纠正我。 你需要
{-# LANGUAGE TypeFamilies #-}
然后我们可以定义一个包含本地类型同义词的类, TypeConv
是我们的类型函数:
class Lift a where
type TypeConv a
liftOp :: a -> TypeConv a
然后我们可以做一个实例
instance Lift Int where
type TypeConv Int = TestData (Cont Int)
liftOp i = TestData (Cont i)
如果我们只想包装Cont
,我们可以做到
instance Lift Integer where
type TypeConv Integer = Cont Integer
liftOp i = Cont i
你可以发疯了
instance Lift Char where
type TypeConv Char = [String]
liftOp c = replicate 4 (replicate 5 c)
这让你有
*Main> liftOp (5::Int)
TestData (Cont 5)
*Main> liftOp (5::Integer)
Cont 5
*Main> liftOp '5'
["55555","55555","55555","55555"]
安德鲁对fundeps
肯定是不必要的批评,类型函数更容易,但功能依赖通常提供额外的灵活性。 在这种情况下,您只需接受更长的类定义
{-# LANGUAGE KindSignatures,
FunctionalDependencies,
FlexibleInstances,
FlexibleContexts #-}
newtype TestData a b = TestData b
newtype Cont a = Cont a
class TypeConv (repr :: * -> *) a b | repr a -> b
class TypeConv repr a b => Lift repr a b | repr a -> b where
liftOp :: a -> repr b
instance TypeConv (TestData a) Int (Cont Int)
instance Lift (TestData a) Int (Cont Int) where
liftOp i = TestData (Cont i)
当然,基于类型函数的方法确实看起来更好,并且可能更可取。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.