如何使用类型和为什么编译器抱怨无限类型?

时间:2017-09-13 08:48:29

标签: haskell

我有以下类型:

newtype Moi s a =
  Moi { runMoi :: s -> (a, s) }  

数据构造函数需要一个函数作为参数,它应该返回一个元组。

我试过以下:

*OwnState> :t Moi (+1)

编译器抱怨:

<interactive>:1:6: error:
    * Occurs check: cannot construct the infinite type: s ~ (a, s)
      Expected type: s -> (a, s)
        Actual type: (a, s) -> (a, s)
    * In the first argument of `Moi', namely `(+ 1)'
      In the expression: Moi (+ 1)

首先查看(+1)的类型签名:

*OwnState> :t (+1)
(+1) :: Num a => a -> a

类型a必须是Num类型类的约束。

所以当我写Moi (+1)时,会发生什么,这种类型将如何替代?

让我们分析错误信息,作为下一步:

Occurs check: cannot construct the infinite type: s ~ (a, s)

Tilde意味着~类型相等以及编译器如何得出s(a, s)具有相同类型的结论?

我想,上面例子的类型替换就是这样的:

n -> n "Type of (+1)
|    |
s -> (a, s)

然后s变为(a, s)且证明s ~ (a, s)为真。

(a, s) -> (a, s)

但是我看不出,为什么它是无限型。

1 个答案:

答案 0 :(得分:7)

  

但是我看不出,为什么它是无限型。

因为s同时出现在类型相等~的左侧和右侧,并且这是以递归方式出现的。在一次替换后,我们有:

s ~ (a,s)

但请注意,s中的(a,s)也应该被替换,所以:

s ~ (a,s) ~ (a,(a,s)) ~ (a,(a,(a,s))) ~ ...

因此,为了构造这种类型,它将导致一个具有无限嵌套2元组的类型。 Haskell无法处理这类类型。

Moi (+1)与“州monad ”的规格不符。您可能想要使用:

Moi (\x -> (x,x+1))

或:

Moi (ap (,) (1 +))