繁体   English   中英

为什么GHC需要功能依赖性来推断此表达式的类型

[英]Why does GHC needs a functional dependency to infer the type of this expression

考虑从此处获取的功能依赖项的示例

class Extract container elem | container -> elem where
  extract :: container -> elem

instance Extract (a,b) a where
  extract (x,_) = x

我理解为什么需要在containerelem之间建立函数依赖关系以避免与

instance Extract (a,b) b where
  extract (x,_) = x

但是,如果我们没有后一种情况,为什么编译器不能计算出extract ('x', 3)类型extract ('x', 3)而不是返回以下错误?

<interactive>:408:1:
Could not deduce (Num t0)
from the context (Num t, Extract (Char, t) elem)
  bound by the inferred type for ‘it’:
             (Num t, Extract (Char, t) elem) => elem
  at <interactive>:408:1-20
The type variable ‘t0’ is ambiguous
When checking that ‘it’ has the inferred type
  it :: forall elem t. (Num t, Extract (Char, t) elem) => elem
Probable cause: the inferred type is ambiguous

我试图做extract('x', 3 :: Int) ,在这种情况下,它会产生错误:

<interactive>:409:1:
No instance for (Show a0) arising from a use of ‘print’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
  instance Show a => Show (Control.Applicative.Const a b)
    -- Defined in ‘Control.Applicative’
  instance Show a => Show (Control.Applicative.ZipList a)
    -- Defined in ‘Control.Applicative’
  instance Show a => Show (Data.Complex.Complex a)
    -- Defined in ‘Data.Complex’
  ...plus 149 others
In a stmt of an interactive GHCi command: print it

在这种情况下,GHC需要功能依赖的局限性是什么?

谢谢

我发现在类型检查器出现歧义时使用:t会有所帮助。

:set -XMultiParamTypeClasses 
:set -XFunctionalDependencies 
:set -XFlexibleContexts 
:set -XFlexibleInstances 

class Extract big small where extract :: big -> small
instance Extract (a, b) a where extract = fst

因此,顺便说一句:

:t let oneTwo = (1, 2) :: (Int, Int)
:t extract oneTwo
extract oneTwo :: Extract (Int, Int) small => small

注意! 即使编译器知道Extract (Int, Int) small是唯一的实例,它也不会使用该信息进行类型解析。 顺序词:

:t {- in an alternate universe -} extract oneTwo
extract oneTwo :: Int

原因很微妙:您实际上不希望这种行为。 如果使用了该信息,则该编译器或二进制文件可能会在星期五执行某些操作,而周一未执行该操作。 因为我可以定义

{- in an alternate universe -}
instance Extract (a, b) a where
  extract = fst
instance Extract (a, b) String where
  extract = const "hey girl"

现在extract oneTwo可以执行以下两项操作之一:

  • :: Int:: String之间任意选择。 这违反了最小惊讶原则。 在点A定义的实例设法对一直在点B定义的代码起作用。

  • 错误出! 违反了最小惊讶原则。 在点A定义的实例使代码一直在点B停止进行类型检查。

因此,面对两个弊端,我们所能做的就是不使用实例来解析类型。

承诺,诺言

现在,如果您保证永远不会出现第二个实例怎么办?

class Extract' big small | big -> small where
  extract' :: big -> small

instance Extract' (a, b) a where
  extract' = fst

:t extract' oneTwo
extract oneTwo :: Int

现在恰好有一个或零情况下Extract' big small为每一个选择big 现在可以使用实例进行类型解析。 有关更多信息,请参见《 GHC扩展的24天》

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM