字符串转IO字符串(有条件的mapM)

4

我正在处理我的第一个Haskell工具(耶!),但是我似乎找不到解决这个问题的方法。大多数文章讨论如何将String转换为IO String,但实际上我需要做相反的操作,因为我在mapM中有条件地使用readFile

我确定有更好的方法来解决这个问题,但是这是我目前所拥有的。这解析了一个源文件(非相关语言)并用包含文件的实际内容替换#include语句。

replaceInclude :: String -> IO String
replaceInclude contents = do
    f_lines <- mapM
            (\l ->
                if (isInfixOf "#include" l)
                then readFile (parseIncludePath l)
                else l -- !! This is the problem line !!
            )
            (lines contents)
   
    return (unlines f_lines)

正如在评论中指出的,问题出在else语句上,它返回一个String类型,但mapM函数需要一个IO String类型。

非常感谢任何帮助,我相信我必须以“Haskell方式”重新思考这个问题 :)

编译错误:

* Couldn't match type `[]' with `IO'
  Expected type: IO String
    Actual type: [Char]

2
尝试使用 pure / return(同一件事) - FrownyFrog
@FrownyFrog 哈哈,我刚刚想到了,太简单了。已回答 :) - scx
2
如果你import Data.Traversable,你可以写成f_lines <- for (lines contents) $ \l -> if ....for大致上是将参数翻转的mapM - chi
@chi ty!我可以问一下吗?我看到在很多地方都使用了$.,但是还没有弄清它们的含义,你能简单解释一下吗? - scx
1
$ 是一个函数应用操作符:f $ x 表示 f x。它主要用于避免在某些情况下使用括号,例如 f (g x y) 可以变成 f $ g x y。而 . 则是函数组合:f . g 表示 (\x -> f (g x))。如果你是初学者,不必过于担心它们——一开始很容易误用并产生错误。上面,我建议在 for 的最后一个参数中使用 $,因为它是多行的,避免使用括号看起来更好看。 - chi
显示剩余2条评论
1个回答

2

哇,这个问题非常简单,解决方案是 else return l

留给后人和初学者的提示: 在 Haskell 中,return 函数创建了一个带有 IO 标记类型的对象。出于某些原因,它是这种类型。这篇Haskell 简明教程中的文档详细而清晰。


3
在这个上下文中,return会产生一个IO String值,因为你正在使用IO单子。 return适用于所有的单子。例如,return 3 :: Maybe Int == Just 3return 3 :: [Int] == [3]等。 - chepner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接