Haskell Monads中`let .. in do`和`<-`表示法有什么区别?

Tom*_*bus 1 monads haskell compiler-errors type-mismatch do-notation

我正在尝试实现一个将字符串转换为Maybe Ints列表的函数,例如readInts "1 2 42 foo" = [Just 1,Just 2,Just 42,Nothing].

我的第一个方法是:

readInts (s::String) = do {
    ws <- words s;
    return (map (readMaybe::(String -> Maybe Int)) ws)
}
Run Code Online (Sandbox Code Playgroud)

这导致以下错误:

lab_monad.hs:20:52:
    Couldn't match type ‘Char’ with ‘[Char]’
    Expected type: [String]
      Actual type: String
    In the second argument of ‘map’, namely ‘ws’
    In the first argument of ‘return’, namely
      ‘(map (readMaybe :: String -> Maybe Int) ws)’
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)

我接下来(和工作)尝试的是:

readInts (s::String) = do {
    let ws = (words s) in do
        return (map (readMaybe::(String -> Maybe Int)) ws)
} 
Run Code Online (Sandbox Code Playgroud)

我的问题是,words s显然属于类型[String].为什么口译员说这是一个String?我对<-运营商不了解的是什么?

che*_*ner 5

ws <- words s在列表单子,不确定地分配一个从字words sws; 剩下的代码只使用那个单词,而return"魔法"功能将处理所有单词的结果合并到结果列表中.

readInts s = do
   ws <- words s  -- ws represents *each* word in words s
   return (readMaybe ws)
Run Code Online (Sandbox Code Playgroud)

do符号只是使用一元语法糖bind:

readInts s = words s >>= (\ws -> return (readMaybe ws))
Run Code Online (Sandbox Code Playgroud)

不使用Monad列表实例,您可以使用map相同的函数应用于每个单词.

readInts s = map readMaybe (words s)
Run Code Online (Sandbox Code Playgroud)

let另一方面,它只是为另一个表达式中使用的更复杂的表达式提供了一个名称.它可以被认为是用于定义和立即应用匿名函数的语法糖.那是,

let x = y + z in f x
Run Code Online (Sandbox Code Playgroud)

相当于

(\x -> f x) (y + z)
  ^     ^      ^
  |     |      |
  |     |      RHS of let binding
  |     part after "in"
  LHS of let binding
Run Code Online (Sandbox Code Playgroud)

let具有多个绑定的语句等同于嵌套let语句:

let x = y + z
    a = b + c
in x + a
Run Code Online (Sandbox Code Playgroud)

相当于

let x = y + z
in let a = b + c
   in x + a
Run Code Online (Sandbox Code Playgroud)

不好意思

(\x -> (\a -> x + a)(b + c))(y + z)
Run Code Online (Sandbox Code Playgroud)