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

Che*_*tan 2 haskell typeclass functional-dependencies

我试图使用类型类和函数依赖得到一个类型的功能,可以改变发言权,IntCont 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)
Run Code Online (Sandbox Code Playgroud)

这是来自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)
Run Code Online (Sandbox Code Playgroud)

鉴于该TypeConv类型类具有fundep我读作:"由于repra,我们可以推断出b"并提供了实例Int,为什么不能GHC推断a' ~ Cont Int

And*_*ewC 6

如果你想要一个类型函数,请使用Type Families - 这就是它们的用途.家庭类型很容易,做你期望的.

通常编译器不推断您的类型的原因是您指定了函数依赖(逻辑关系)而不是函数(计算工具).使用fundeps是出了名的反直觉,部分原因是你在类型级别进行逻辑编程,同时在价值级别进行函数式编程.开关!使用类型级别的函数,具有可爱的Type Families扩展.配有免费的lambda冰箱磁铁,只有四个令牌(不包括p&p).


我不确定你想要达到的目的,但这里有一个例子 - 如果我朝错误的方向前进,请纠正我.你需要

{-# LANGUAGE TypeFamilies #-}
Run Code Online (Sandbox Code Playgroud)

然后我们可以定义一个包含本地类型同义词的类,TypeConv这是我们的类型函数:

class Lift a where
    type TypeConv a
    liftOp :: a -> TypeConv a
Run Code Online (Sandbox Code Playgroud)

然后我们可以做一个实例

instance Lift Int where
    type TypeConv Int = TestData (Cont Int)
    liftOp i = TestData (Cont i)
Run Code Online (Sandbox Code Playgroud)

如果我们只想包装Cont,我们可以做到

instance Lift Integer where
    type TypeConv Integer = Cont Integer
    liftOp i = Cont i
Run Code Online (Sandbox Code Playgroud)

你可以发疯了

instance Lift Char where
    type TypeConv Char = [String]
    liftOp c = replicate 4 (replicate 5 c)
Run Code Online (Sandbox Code Playgroud)

这让你有

*Main> liftOp (5::Int)
TestData (Cont 5)

*Main> liftOp (5::Integer)
Cont 5

*Main> liftOp '5'
["55555","55555","55555","55555"]
Run Code Online (Sandbox Code Playgroud)