let 里面的 Monadic do 记法,可能吗?

Monadic do notation inside let, is it possible?

考虑以下有效的 Haskell 代码

module Main where

main :: IO ()
main = do
  let x = f
  print x

f :: Maybe (Int, Int)
f =
  Just 3 >>= (\a ->
    Just 5 >>= (\b ->
      return (a, b)))

其中函数 f 可以用这样的 do-notation 等效地重写

f :: Maybe (Int, Int)
f = do
  a <- Just 3
  b <- Just 5
  return (a, b)

令我烦恼的是,当我将 f 的内容内联时,do 符号将不起作用。以下代码甚至不解析:

main :: IO ()
main = do
  let x = do
    a <- Just 3
    b <- Just 5
    return (a, b)
  print x

我是否纠正了在 let 中我被迫求助于 (>>=)

虽然我在处理它,但以下代码也无法解析:

module Main where

main :: IO ()
main = do
  let x =
    Just 3 >>= (\a ->
      Just 5 >>= (\b ->
        return (a, b)))
  print x

除了 let 的不必要的限制能力外,我看不出明显的原因。在 let 中有使用 bind 的优雅方法吗?

Am I correct that inside let I am forced to resort to (>>=)?

否:

main :: IO ()
main = do
  let x = do
      a <- Just 3
      b <- Just 5
      return (a, b)
  print x

Haskell 的 layout 规则规定 p = e 中的绑定 e 的主体必须至少与 [=18] 的开头一样=](或第一个绑定,如果您同时使用多个)。由于 do 中的 let 遵循(几乎)与 let … in 相同的规则,您可以使用以下函数验证这一点:

f :: Int
f = 
  let x =
    3 + 5
  in x

这不起作用,因为 3 + 5 没有与 x 相同或更高的缩进级别。然而,

f :: Int
f =
  let x =
       3 + 5
  in x

有效。此外,虽然上面的 main 有效,但它并没有真正表达 abxdo 块中的东西,所以它是稍微缩进一点更好:

main :: IO ()
main = do
  let x = do
        a <- Just 3
        b <- Just 5
        return (a, b)
  print x