在Hindley-Milner中```推论

时间:2017-06-12 21:41:58

标签: haskell clojure hindley-milner

我试图通过在我经常使用的语言Clojure中实现算法W来自学Hindley-Milner类型。我遇到let推断的问题,我不确定我做错了什么,或者我期望的结果是否需要算法以外的东西。< / p>

基本上,使用Haskell表示法,如果我试图推断出它的类型:

\a -> let b = a in b + 1

我明白了:

Num a => t -> a

但我应该得到这个:

Num a => a -> a

同样,我实际上是在Clojure中这样做,但我不相信问题是特定于Clojure的,所以我使用Haskell表示法使其更清晰。当我在Haskell中尝试时,我得到了预期的结果。

无论如何,我可以通过将每个let转换为函数应用程序来解决该特定问题,例如:

 \a -> (\b -> b + 1) a

然后我失去了let多态性。由于我没有HM的任何先验知识,我的问题是我是否在这里遗漏了一些东西,或者这是否与算法的工作方式有关。

修改

如果有人遇到类似的问题,并想知道我是如何解决的,那么我就是关注Algorith W Step By Step。在第2页的底部,它表示&#34;将 Types 方法扩展到列表有时会很有用。&#34;因为它对我来说并不是强制性的,所以我决定跳过那部分并稍后重新审视。

然后我将ftv TypeEnv函数直接翻译成Clojure,如下所示:(ftv (vals env))。由于我已将ftv作为cond表单实施,并且没有seq的条款,因此它只返回nil (vals env)。这当然正是静态类型系统设计要捕获的那种错误!无论如何,我刚刚将ftv中与env地图相关的条款重新定义为(reduce set/union #{} (map ftv (vals env)))并且它有效。

1 个答案:

答案 0 :(得分:6)

很难说出错是什么,但我猜你的概括是错误的。

让我们手动输入字词。

__bridge

首先,我们将\a -> let b = a in b + 1 与新的类型变量相关联,例如a

然后我们输入a :: t0。我们也得到b = a

但是,这是关键点,我们应该b :: t0的类型概括为b。这是因为我们只能对环境中没有出现的tyvar进行概括:在这里,我们确实在b :: forall t0. t0中存在t0

如果你对它进行概括,你会得到一种a :: t0的通用类型。然后b变为b+1,整个字词变为b+1 :: forall t0. Num t0 => t0,因为forall t0 t1. Num t1 => t0 -> t1a的类型不相关(b,一旦推广,可以被alpha转换为t0)。