将do语句理解为参数

时间:2017-09-25 10:19:36

标签: haskell

我有以下代码段:

  main = scotty 3000 $ do
    get "/:word" $ do
      beam <- param "word"
      putStrLn "hello"
      html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]  

我明白,do语句是如何工作的,它只是>>=的语法糖,但上面的例子,怎么可能,我可以将do块作为功能参数?

2 个答案:

答案 0 :(得分:3)

让我们来定义

twice :: IO () -> IO ()
twice a = do
   a
   a

......或简称twice a = a>>a

你当然可以使用

Prelude> twice (putStrLn "hello")
hello
hello

...但是Haskellers喜欢保存parens并写twice $ putStrLn "hello"

您也可以像

一样使用它
Prelude> twice $ putStrLn "hello" >> putStrLn "world"
hello
world
hello
world

现在,该monadic序列可以转换为do块:

Prelude> twice $ do{putStrLn "hello"; putStrLn "world"}

并且使用布局而不是大括号和分号,因此看起来如此:

Prelude> :{
Prelude| twice $ do
Prelude|    putStrLn "hello"
Prelude|    putStrLn "world"
Prelude| :}
hello
world
hello
world

答案 1 :(得分:1)

http://www.haskellforall.com/2014/10/how-to-desugar-haskell-code.html提供了几个示例来说明各种do表达式是如何被删除的。

单一表达

do
  beam <- param "word"
  putStrLn "hello"
  html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]

首先被递归地移植到多个嵌套表达式中:

do
  beam <- param "word"
  do putStrLn "hello"
     html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"]  

内部使用>>运算符进行desugars:

do
  beam <- param "word"
  (putStrLn "hello" >> html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"])

使用>>=生成的表达式desugars:

param "word" >>= (\beam -> (putStrLn "hello" >> html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"])

表达式被视为get "/:word"的参数:

main = scotty 3000 $ do
  get "/:word" $ param "word" >>= (\beam -> (putStrLn "hello" >> html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"])

最后剩下的do表达非常简单地去了

main = scotty 3000 $ get "/:word" $ param "word" >>= (\beam -> (putStrLn "hello" >> html $ mconcat ["<h1>Scotty, ", beam, " me up!</h1>"])

作为单行do表达式只是包装表达式本身(do x = x)。