![](/img/trans.png)
[英]Haskell: Why does GHC not infer type in this typeclass with fundeps?
[英]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
我理解为什么需要在container
和elem
之间建立函数依赖关系以避免与
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.