Haskell Reader monad 和参数传递

gec*_*kos 6 haskell

我正在关注本教程https://blog.ssanj.net/posts/2014-09-23-A-Simple-Reader-Monad-Example.html

它的树功能让我很尴尬

tom :: Reader String String
tom = do
  env <- ask
  return (env ++ " This is tom.")

jerry :: Reader String String
jerry = do
  env <- ask
  return (env ++ " This is Jerry.")

tomAndJerry :: Reader String String
tomAndJerry = do
   t <- tom
   j <- jerry
   return (t ++ "\n" ++ j)

runJerryRun :: String
runJerryRun  = (runReader tomAndJerry) "Who is this?"
Run Code Online (Sandbox Code Playgroud)

这些函数不接收任何参数,但它们仍然访问 reader monad,这里发生了什么魔法?这背后的直觉是什么?

我的读者monad是一种全局的?

Jiv*_*van 3

前两个函数均返回其自己的 Reader monad 实例。然后,您可以将它们组合在一起(在第三个函数中)。

为了论证,让我们替换ReaderIO并做类似的事情,这些函数都不接收任何参数:

getIntFromFile :: IO Int
getIntFromFile = do
    x <- readFile "myfile.txt"
    pure $ read x :: Int

getIntFromStdin :: IO Int
getIntFromStdin = do
    x <- getLine
    pure $ read x :: Int
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,两者都使用IOmonad,但它们没有任何共同点。但是,由于它们都使用IOmonad,因此您可以(这就是它的优点)将它们组合在一起,如下所示:

-- | the equivalent of your `tomAndJerry` function
main :: IO ()
main = do
    x <- getIntFromFile
    y <- getIntFromStdin
    print $ x + y
Run Code Online (Sandbox Code Playgroud)

这与教程中的示例的逻辑完全相同,除了使用Reader代替IO