【发布时间】:2011-04-23 12:50:13
【问题描述】:
如何使用 writeFile 将 [String] 写入其中?
例如我有["one", "two", "three"]
我想进入文件:
one two three
如何用 haskell 做到这一点?如果需要,我可以编写一个附加函数。
【问题讨论】:
-
到目前为止你尝试过什么?你知道mapM吗?你知道如何将单个字符串写入文件吗?
如何使用 writeFile 将 [String] 写入其中?
例如我有["one", "two", "three"]
我想进入文件:
one two three
如何用 haskell 做到这一点?如果需要,我可以编写一个附加函数。
【问题讨论】:
我建议使用unwords :: [String] -> String 而不是intersperse。我想简单地回答以下简单的例子,使用ghci:
Prelude> let ss = ["one", "two", "three"]
Prelude> writeFile "myfile" $ unwords ss
Prelude> readFile "myfile"
"one two three"
【讨论】:
这不是说Tarrasch和prnr没说什么,但困难在于没有将IO与纯函数分开:你说
我有
["one", "two", "three"],我想把它写成一个文件:one two three。
您有一个字符串列表,并且想要做某事,即您正在寻找一个函数lkndfhu :: [String] -> IO ()。确实如此,但如果你问:
我要写入(新)文件的内容是什么?
您会注意到它与本例中的情况相同:
我想写入标准输出的内容是什么?
我要附加到文件 file.txt 的内容是什么?
嗯,它是"one two three" :: String。你想要将["one", "two", "three"] 映射到"one two three" 的东西,别管你要用"one two three" 做什么
所以你真的在寻找一个函数lkndfhu_pure :: [String] -> String,你可以用putStrLn或writeFile filename组成String -> IO ()类型的函数
前奏函数concat :: [String] -> String 具有正确的类型,但它会产生"onetwothree" 并且文件或标准输出将如下所示:
一二三
Prelude 函数 unlines :: [String] -> String 具有正确的类型,但会产生 `"one\ntwo\nthree" 并且文件看起来像这样:
一个
两个
三
您想要的预先给定的 Prelude [String] -> String 函数是 unwords,如 Tarrasch 注释;但正如pmr 注释unwords 和unlines 都是concat :: [[a]] -> [a] 和intersperse :: a -> [a] -> [a] 的组合——基本上:
unwords mystrings = concat (intersperse " " mystrings)
unlines mystrings = concat (intersperse "\n" mystrings)
或者,等价的,
unwords = concat . intersperse " "
unlines = concat . intersperse "\n"
(这些不是 Prelude 实际使用的定义。)正如 pmr 所指出的,intersperse 的抽象性意味着它可以以复杂的方式与 IO 一起使用,但没有迹象表明这就是你需要。请注意,unwords unlines 和 intersperse 具有更高级的类似字符串类型的变体,例如ByteString 和 Text
如果您想在传递给 IO 之前考虑与使用纯函数一致的文档准备,您可以查看 Haskell 平台附带的漂亮打印库(还有很多其他的)。在 ghci 中输入 :m +Text.PrettyPrint,然后输入 :browse 。 ghci(和 Hugs)以特殊方式实现 Doc 类型,因此评估表达式会显示 Doc,因为如果将其呈现为字符串并将其写入文件,则会出现在读者面前:
PrettyPrint> let lknfdhu_strings = ["one", "two", "three"]
PrettyPrint> :t lknfdhu_strings
lknfdhu_strings :: [String]
PrettyPrint> let lknfdhu = map text lknfdhu_strings
PrettyPrint> :t lknfdhu
lknfdhu :: [Doc]
PrettyPrint> hcat lknfdhu
onetwothree
PrettyPrint> hsep lknfdhu
one two three
PrettyPrint> vcat lknfdhu
one
two
three
PrettyPrint> let looksGood = hsep lknfdhu
PrettyPrint> :t render
render :: Doc -> String
PrettyPrint> render looksGood
"one two three"
PrettyPrint> render (vcat lknfdhu)
"one\ntwo\nthree"
PrettyPrint> let dash = " - "
PrettyPrint> let dashdoc = text dash
PrettyPrint> dash
" - "
PrettyPrint> dashdoc
-
PrettyPrint> hcat ( punctuate dashdoc lknfdhu )
one - two - three
PrettyPrint> hcat ( punctuate (text " ") lknfdhu )
one two three
PrettyPrint> writeFile "lknfdhu.txt" (render looksGood)
这些示例当然非常原始,请查看 :browse 的所有疯狂函数以及文档中的示例
【讨论】:
使用 intersperse 获取单词之间的空格并将列表中的每个字符串附加到 path 的文件中,其中 xs 是您的单词列表:
mapM_ (appendFile path) (intersperse " " xs)
将字符串列表展平并立即写入可能会更快:
writeFile path (concat (intersperse " " xs))
虽然我觉得第一个更自然。
编辑:请注意,如果文件已经包含某些内容,第一个和第二个变体仍然会做不同的事情。 writeFile 将简单地写入一个新文件,而 appendFile 将附加到现有内容。目前尚不清楚您真正想要哪种行为。
【讨论】:
我很惊讶没有人提到插入,这与 concat 和 intersperse 相同。
【讨论】: