MultiParamTypeClasses的类型推断?

Ala*_*aya 0 haskell

我正在写一些我认为显然是正确的代码,但似乎GHC并不这么认为:

class Convert a b where
    convert :: a -> b
class (Convert a b, Convert b c) => F a b c where 
    f  :: a -> c
    f = f2 . f1 
      where f2 = convert :: b -> c
            f1 = convert :: a -> b
Run Code Online (Sandbox Code Playgroud)

上面的代码给出了这样的错误信息,所以我想知道GHC在尝试推断出合适的类型时遇到了什么困难,或者我是否必须提供GHC更多的类型信息?

Main.hs:53:18:
    Could not deduce (Convert b2 c2) ac)
      bound by the class declaration for ‘F’ at Main.hs:(50,1)-(54,34)
    Possible fix:
      add (Convert b2 c2) to the context of
        an expression type signature: b2 -> c2
    In the expression: convert :: b -> c
    In an equation for ‘f2’: f2 = convert :: b ->    where
              f2 = convert :: b -> c
              f1 = convert :: a -> b

Main.hs:54:18:
    Could not deduce (Convert a2 b2) arising from a use of ‘convert’
    from the context (F a b c)
      bound by  Possible fix:
      add (Convert a2 b2) to the context of
        an expression type signature: a2 -> b2
    In the expression: convert :: a -> b
    In an equation for ‘f1’: f1 = convert :: a -> b
    In an equation for ‘f’:
        f = f2 . f1
          where
              f2 = convert :: b -> c
              f1 = convert :: a -> b
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)

jos*_*uan 6

无论f1f2使用b,但是这是免费的(不受限的f).怎么ghci判断b

您可以使用ScopedTypeVariables"链接"b类型上f1,并f2bclass约束

{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
class Convert a b where
    convert :: a ?  b
class (Convert a b, Convert b c) ?  F a b c | a c ? b where -- #1
    f  :: a ?  c
    f = f2 . f1
      where f2 = convert :: ? b . F a b c ? b ?  c -- #2
            f1 = convert :: ? b . F a b c ? a ?  b -- #3

instance Convert Int String where
  convert = show
instance Convert String Double where
  convert = read
instance F Int String Double where
Run Code Online (Sandbox Code Playgroud)

现在

> f (34 :: Int) :: Double
34.0
Run Code Online (Sandbox Code Playgroud)

没有#1上ScopedTypeVariablesb类型名称,#2和#3都是不同的(#2和#3推断相同f2 . f1).与ScopedTypeVariables所有(#1,#2和#3)是相同的类型.

另一方面,FunctionalDependencies需要b从两个给定中选择a,c因为f没有关于它的信息.

最后,看看到@leftaroundabout响应,如果可以的话,看起来更好指定b的类型f使用幻象类型约束.

(相关问题如何在两个分离的表达式之间调和/约束类型)