我写了这个简单的函数,它接受两个文件名(String),并将第一个文件的内容写入第二个文件,将toUpper
应用于每个字符。
import Data.Char
ioFile f1 f2 = do
s <- readFile f1
sUp <- [toUpper c | c <- s]
writeFile f2 sUp
但是翻译会引发错误
Couldn't match expected type ‘IO String’ with actual type ‘[Char]’
In a stmt of a 'do' block: sUp <- [toUpper c | c <- s]
In the expression:
do { s <- readFile f1;
sUp <- [toUpper c | c <- s];
writeFile f2 sUp }
In an equation for ‘ioFile’:
ioFile f1 f2
= do { s <- readFile f1;
sUp <- [toUpper c | c <- s];
writeFile f2 sUp }
如何将s
用作[Char]
代替IO String
?
答案 0 :(得分:2)
你无法绑定纯粹的&#39;像sUp <- [toUpper c | c <- s]
这样的值。请注意,与接受的答案所表明的不同,这并不意味着您无法为其命名。首先,return
函数将纯值提升为IO
(或任何monad,但我们现在正在IO
),所以{ {1}} 工作。还有let语法的变体,它几乎就是这样做的:sUp <- return [toUpper c | c <- s]
。
答案 1 :(得分:0)
第二行不是IO Monadic操作,它只是列表理解,所以你应该把它写成:
import Data.Char
ioFile f1 f2 = do
s <- readFile f1
writeFile f2 [toUpper c | c <- s]
Haskell社区的一个重要部分32x32,因此更愿意看到:
ioFile f1 f2 = readFile f1 >>= \s -> writeFile f2 $ map toUpper s
甚至更短:
ioFile f1 f2 = readFile f1 >>= writeFile f2 . map toUpper
使用considers do
harmful将给定函数(在本例中为toUpper
)应用于给定列表的每个元素并生成结果列表。 map :: (a -> b) -> [a] -> [b]
非正式地等同于在左monad的“结果”上调用给定的右操作数函数。所以c >>= f
相当于:
do
x <- c
f x