Dán*_*ein 3 io monads dictionary haskell pandoc
我正在尝试学习Haskell的基础知识,同时为Pandoc开发一个过滤器,以递归方式包含其他markdown文件.
基于脚本指南,我能够创建一个有点工作的过滤器.这将查找带有include类的CodeBlocks 并尝试包含引用文件的AST.
```include
section-1.md
section-2.md
#pleasedontincludeme.md
```
Run Code Online (Sandbox Code Playgroud)
整个过滤器和输入源可以在以下存储库中找到:steindani/pandoc-include(或见下文)
可以使用过滤器运行pandoc,并使用以下命令以markdown格式查看输出: pandoc -t json input.md | runhaskell IncludeFilter.hs | pandoc --from json --to markdown
我注意到map函数(在第38行) - 尽管获取要包含的文件列表 - 只调用第一个元素的函数.这不是唯一奇怪的行为.包含的文件也可以包含一个处理的包含块,并包含引用的文件; 但它不会更深入,忽略最后一个文件的包含块.
为什么map函数不遍历整个列表?为什么它在2级层次结构后停止?
请注意,我刚刚开始学习Haskell,我确信我犯了错误,但我很高兴学习.
谢谢
完整源代码:
module Text.Pandoc.Include where
import Control.Monad
import Data.List.Split
import Text.Pandoc.JSON
import Text.Pandoc
import Text.Pandoc.Error
stripPandoc :: Either PandocError Pandoc -> [Block]
stripPandoc p =
case p of
Left _ -> [Null]
Right (Pandoc _ blocks) -> blocks
ioReadMarkdown :: String -> IO(Either PandocError Pandoc)
ioReadMarkdown content = return (readMarkdown def content)
getContent :: String -> IO [Block]
getContent file = do
c <- readFile file
p <- ioReadMarkdown c
return (stripPandoc p)
doInclude :: Block -> IO [Block]
doInclude cb@(CodeBlock (_, classes, _) list) =
if "include" `elem` classes
then do
files <- return $ wordsBy (=='\n') list
contents <- return $ map getContent files
result <- return $ msum contents
result
else
return [cb]
doInclude x = return [x]
main :: IO ()
main = toJSONFilter doInclude
Run Code Online (Sandbox Code Playgroud)
我可以在你的doInclude函数中发现以下错误:
doInclude :: Block -> IO [Block]
doInclude cb@(CodeBlock (_, classes, _) list) =
if "include" `elem` classes
then do
let files = wordsBy (=='\n') list
let contents = map getContent files
let result = msum contents -- HERE
result
else
return [cb]
doInclude x = return [x]
Run Code Online (Sandbox Code Playgroud)
由于整个函数的结果类型是IO [Block],我们可以向后工作:
result 有类型 IO [Block]contents 有类型 [IO [Block]]msum 正在使用类型 [IO [Block]] -> IO [Block]而第三部分是问题 - 在你的程序中,有一个非标准的MonadPlus实例被加载IO,我打赌它的作用msum contents是:
这不是标准MonadPlus实例,因此它来自您要导入的其中一个库.我不知道哪个.
这里的一般建议是:
因为这里的问题似乎msum是使用与您期望的类型不同的类型.通常这会产生类型错误,但在这里你运气不好,它与某个库中的奇怪类型类实例进行交互.
从评论中,您的意图msum contents是创建一个IO按顺序执行所有子动作的动作,并将其结果作为列表收集.好吧,这个MonadPlus类通常IO不是为它定义的,当它正在做的时候.所以这里使用的正确函数是sequence:
-- Simplified version, the real one is more general:
sequence :: Monad m => [m a] -> m [a]
sequence [] = return []
sequence (ma:mas) = do
a <- ma
as <- mas
return (a:as)
Run Code Online (Sandbox Code Playgroud)
这让你从[IO [Block]]到IO [[Block]].要消除双嵌套列表,您只需使用内部fmap应用.concatIO
| 归档时间: |
|
| 查看次数: |
255 次 |
| 最近记录: |