[英]Haskell: Why does GHC not infer type in this typeclass with fundeps?
I'm trying to use typeclasses and functional dependencies to get a type function that can transform say, Int
to Cont Int
in the code below, then use it in another typeclass as shown below. 我正在尝试使用类型类和函数依赖项来获取一个类型函数 ,可以在下面的代码中将
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)
And here's the error from ghci 7.4.2 这是来自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)
Given that the TypeConv
typeclass has a fundep that I read as: "Given repr
and a
, we can infer b
" and provided an instance for Int
, why can't ghc infer that a' ~ Cont Int
? 鉴于
TypeConv
类型类有一个fundep我读作:“给定repr
和a
,我们可以推断b
”并为Int
提供了一个实例,为什么ghc不能推断a' ~ Cont Int
?
If you want a type function, use Type Families - that's what they're for. 如果你想要一个类型函数,请使用Type Families - 这就是它们的用途。 Type Families are easy and do what you expect.
家庭类型很容易,做你期望的。
Often the reason that the compiler didn't infer your type is that you specified a functional dependency (logical relationship) rather than a function (calculating tool). 通常编译器不推断您的类型的原因是您指定了函数依赖(逻辑关系)而不是函数(计算工具)。 Using fundeps is notoriously counter-intuitive, partly because you're doing logic programming at the type level whilst doing functional programming at the value level.
使用fundeps是出了名的反直觉,部分原因是你在类型级别进行逻辑编程,同时在价值级别进行函数式编程。 Switch!
开关! Use functions at the type level, with the lovely Type Families extension.
使用类型级别的函数,具有可爱的Type Families扩展。 Comes with free lambda fridge magnet with just four tokens (p&p not included).
配有免费的lambda冰箱磁铁,只有四个令牌(不包括p&p)。
I'm not sure what you were trying to achieve, but here's an example - correct me if I'm heading in the wrong direction. 我不确定你想要达到的目的,但这里有一个例子 - 如果我朝错误的方向前进,请纠正我。 You'll need
你需要
{-# LANGUAGE TypeFamilies #-}
Then we can define a class that includes a local type synonym, TypeConv
which is our type function: 然后我们可以定义一个包含本地类型同义词的类,
TypeConv
是我们的类型函数:
class Lift a where
type TypeConv a
liftOp :: a -> TypeConv a
And then we could make an instance 然后我们可以做一个实例
instance Lift Int where
type TypeConv Int = TestData (Cont Int)
liftOp i = TestData (Cont i)
and if we just want to wrap in Cont
, we could do 如果我们只想包装
Cont
,我们可以做到
instance Lift Integer where
type TypeConv Integer = Cont Integer
liftOp i = Cont i
and you can go crazy with 你可以发疯了
instance Lift Char where
type TypeConv Char = [String]
liftOp c = replicate 4 (replicate 5 c)
which lets you have 这让你有
*Main> liftOp (5::Int)
TestData (Cont 5)
*Main> liftOp (5::Integer)
Cont 5
*Main> liftOp '5'
["55555","55555","55555","55555"]
Andrew is unnecessarily critical of fundeps
sure, type functions are easier, but functional dependencies often provide extra flexibility. 安德鲁对
fundeps
肯定是不必要的批评,类型函数更容易,但功能依赖通常提供额外的灵活性。 In this case, you simply have to accept longer class definitions 在这种情况下,您只需接受更长的类定义
{-# 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)
Of course, the type function based approach does look nicer, and is probably preferable. 当然,基于类型函数的方法确实看起来更好,并且可能更可取。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.