IO动作嵌套在未执行的其他monad中

时间:2017-02-22 03:52:29

标签: haskell io-monad

我有一个

foobar :: IO (ParseResult [(String,String)])

ParseResult是这里定义的monad:https://hackage.haskell.org/package/haskell-src-exts-1.13.5/docs/Language-Haskell-Exts-Parser.html#t:ParseResult

我想接受这些字符串并将其写入https://hackage.haskell.org/package/HaTeX-3.17.1.0/docs/Text-LaTeX-Base-Writer.html中定义的LaTeXT m ()

运行此功能会导致无法创建文件。

writeReport2 :: [Char] -> IO (ParseResult (IO ()))
writeReport2 name = do x <- foobar
                       return $ do y <- x
                                   return $ do z <- (execLaTeXT.docAndGraph) y
                                               renderFile fileName z
  where
    fileName = name ++ ".tex"

然而代码:

writeReport :: t -> LaTeXT IO a -> IO ()
writeReport name report = createLatex >>= renderFile fileName
  where
    createLatex = execLaTeXT report
    fileName = "AAAAA" ++ ".tex"


testFoo = [(" | HaskellExample Example File\n | Two examples are given below:\n\n >>> fib 10\n 55\n\n >>> putStrLn \"foo\\nbar\"\n foo\n bar ","fib :: Int -> Int"),("\n | This is a thing: ","fib = undefined"),("\n | This is a thing:\n","fibar :: String -> Float")]

itWorks = writeReport "AAAA.txt" $ docAndGraph testFoo

将创建一个新文件。

两组代码类型检查。

1 个答案:

答案 0 :(得分:3)

我可以writeReport2无需修改就可以工作。

我认为您的问题可能是writeResport2的返回值中的嵌套IO操作

为了展平嵌套的IO操作,我必须使用函数join :: Monad m => m (m a) -> m a from Control.Monad

main :: IO ()
main = join $ fromParseResult <$> writeReport2 "test"

这是我的完整代码:

{-# LANGUAGE OverloadedStrings #-}

module Main where

import           Language.Haskell.Exts.Parser
import           Text.LaTeX.Base.Writer
import           Text.LaTeX
import           Data.String
import           Control.Monad

foobar :: IO (ParseResult [(String, String)])
foobar = return (ParseOk testFoo)

testFoo = [ ( " | HaskellExample Example File\n | Two examples are given below:\n\n >>> fib 10\n 55\n\n >>> putStrLn \"foo\\nbar\"\n foo\n bar "
            , "fib :: Int -> Int"
            )
          , ("\n | This is a thing: ", "fib = undefined")
          , ("\n | This is a thing:\n", "fibar :: String -> Float")
          ]

docAndGraph :: Monad m => [(String, String)] -> LaTeXT m ()
docAndGraph x = do
    documentclass [] article
    document $
        raw (fromString (show x))

writeReport2 :: [Char] -> IO (ParseResult (IO ()))
writeReport2 name = do
    x <- foobar
    return $ do
        y <- x
        return $ do
            z <- (execLaTeXT . docAndGraph) y
            renderFile fileName z
  where
    fileName = name ++ ".tex"

main :: IO ()
main = join $ fromParseResult <$> writeReport2 "test"

加载到GHCi:

$ stack ghci
io-action-nested-in-other-monads-not-executing-0.1.0.0: initial-build-steps (exe)
Configuring GHCi with the following packages: io-action-nested-in-other-monads-not-executing
Using main module: 1. Package `io-action-nested-in-other-monads-not-executing' component exe:io-action-nested-in-other-monads-not-executing with main-is file: /home/sven/dev/stackoverflow-questions/io-action-nested-in-other-monads-not-executing/src/Main.hs
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/sven/.ghc/ghci.conf
[1 of 1] Compiling Main             ( /home/sven/dev/stackoverflow-questions/io-action-nested-in-other-monads-not-executing/src/Main.hs, interpreted )
Ok, modules loaded: Main.
Loaded GHCi configuration from /tmp/ghci22616/ghci-script

运行它:

λ main

创建此文件:

$ cat test.tex 
\documentclass{article}\begin{document}[(" | HaskellExample Example File\n | Two examples are given below:\n\n >>> fib 10\n 55\n\n >>> putStrLn \"foo\\nbar\"\n foo\n bar ","fib :: Int -> Int"),("\n | This is a thing: ","fib = undefined"),("\n | This is a thing:\n","fibar :: String -> Float")]\end{document}%                                                                        

我知道这不是问题的范围,但如果你愿意,你可以绕过嵌套的IO,例如:doinf,例如:

writeReport3 :: [Char] -> IO ()
writeReport3 name = do
    let fileName = name ++ ".tex"
    x <- foobar
    case x of
      ParseOk y -> do
        z <- execLaTeXT (docAndGraph y)
        renderFile fileName z
      ParseFailed _ _ ->
        return ()

main :: IO ()
main = writeReport3 "test"