简体   繁体   English

Haskell:为什么GHC不使用fundeps来推断这个类型类中的类型?

[英]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 IntInt转换为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我读作:“给定repra ,我们可以推断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.

相关问题 为什么这个Haskell代码使用fundeps进行类型检查,但是对类型系列产生了不可触摸的错误? - Why does this Haskell code typecheck with fundeps but produce an untouchable error with type families? Haskell:鼓励GHC推断出正确的中间类型 - Haskell: Encouraging GHC to infer the correct intermediate type 为什么GHC需要功能依赖性来推断此表达式的类型 - Why does GHC needs a functional dependency to infer the type of this expression 为什么GHC在这里推断出单态类型,即使禁用了MonomorphismRestriction? - Why does GHC infer a monomorphic type here, even with MonomorphismRestriction disabled? 为什么GHC会为“ hSetBuffering”的应用推断出“ IO b”的类型? - Why does GHC infer type of `IO b` for an application of `hSetBuffering`? 如何将 TypeApplications 与 typeclass 方法一起使用,为什么 GHCi 会推断出我无法使用的类型? - How do I use TypeApplications with typeclass methods, and why does GHCi infer a type that I can't use? Haskell 如何推断 (+).(+) 的类型 - How does Haskell infer the type of (+).(+) 为什么Haskell中没有`Cofunctor`类型类? - Why there is no `Cofunctor` typeclass in Haskell? Haskell如何推断类型类的定义? - How does Haskell infer definitions for type classes? 为什么Haskell不能推断Tree类型? - Why can't Haskell infer Tree type?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM