我的问题与另一个问题的答案有关:https://stackoverflow.com/a/11766789/3212958
在他的回答中,ertes写下了以下类型的签名
select :: [a] -> [(a, [a])]
但是,当实际使用select
时,ertes会在do
块内写下以下内容
(y, ys) <- select xs
请帮助我阐明元组(y, ys)
如何匹配选择的返回类型,即[(a, [a])]
。 Haskell在某些时候强迫这些类型吗? (Haskell是否强制类型?)<-
是否从(a, [a])
返回的列表monad中提取select
类型的元组?
谢谢, 最大
---编辑:---
@Lee在尝试推理类型之前提醒newbs去desugar。在明确>>=
之后,更清楚的是发生了什么。脱毒后,有问题的功能如下:
select xs >>= \(y, ys) -> fmap (y:) (perms (n - 1) ys)
对于列表,xs >>= f = concat (map f xs)
。因此,在此上下文中更好地阅读(y, ys)
作为映射列表的函数的签名。
答案 0 :(得分:13)
以do
表示法,
do x1 <- action1
action2
已翻译为action1 >>= \x1 -> action2
这意味着如果action1
的某个monad m a
的类型为m
,则x1
的类型为a
。它不是真正强制类型,而是“解包”monadic动作action1
中的值并将其绑定到x1
。
答案 1 :(得分:4)
(y, ys)
的类型为(b, c)
select
的返回类型属于[(a, [a])]
在<-
中,类型实际上是d
和Monad m => m d
。所以我们可以写出以下类型的等式:
(b, c) ~ d
[(a, [a])] ~ Monad m => m d
解决很容易。首先将第一个等式中的d
替换为第二个等式:
[(a, [a])] ~ Monad m => m (b, c)
现在看看发生了什么我将使用[]类型构造函数的前缀形式(它不是有效的haskell,但你应该明白这一点):
[] (a, [a]) ~ Monad m => m ( b, c)
所以
m ~ []
(a, [a]) ~ (b, c)
此时编译器会检查instance Monad [a]
是否存在。其余的很简单:
a ~ b
[a] ~ c