我有以下类型:
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)
但是我看不出,为什么它是无限型。
答案 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 +))