为什么我不能这样做? 禁止在这个问题中使用'do':/ 如何在我的列表中调用单词并同时产生IO? 谢谢..这是我的实际代码:/
main :: IO()
main =
putStr "Name of File: " >>
getLine >>=
\st ->
openFile st ReadMode >>=
\handle ->
hGetContents handle >>=
\y ->
words y >>=
\strings ->
strings !! 1 >>=
\string->
putStr string
[编辑]解决方案:
main :: IO()
main =
putStr "Name of File: " >>
getLine >>=
\st ->
openFile st ReadMode >>=
\handle ->
hGetContents handle >>=
\y ->
return (words y) >>=
\strings ->
return (strings !! 1) >>=
\string->
putStr string
答案 0 :(得分:6)
使用return (words y)
代替words y
。 return
将纯值(例如[String]
返回的words
)包装到monad中。
从你的措辞来看,听起来这个问题就是家庭作业。如果是这样,它应该被标记为。
答案 1 :(得分:6)
(这并没有直接回答这个问题,但它会使你的代码更加惯用,从而更容易阅读。)
你正在使用模式\x -> f x >>= ...
,这可以(并且应该)被消除:它(大部分)是不必要的噪声,它掩盖了代码的含义。我不会使用你的代码,因为它是作业,但请考虑这个例子(注意我正在使用return
,如其他答案所示):
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (lines str) >>=
\lns -> return (length lns) >>=
\num -> print num
(它从用户读取文件名,然后打印该文件中的行数。)
最简单的优化是我们计算行数的部分(这对应于您将单词分开并得到第二行的部分):字符串str
中的行数仅为{ {1}}(与length (lines str)
相同),因此我们没有理由对length . lines $ str
进行调用,并且对length
的调用分开。我们的代码现在是:
lines
现在,下一个优化工作在main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (length . lines $ str) >>=
\num -> print num
。这可以写成\num -> print num
。 (这称为eta conversion)。 (您可以将此视为“一个接受参数并在其上调用print
的函数,与print
本身相同”。现在我们有:
print
我们可以做的下一个优化基于monad laws。使用第一个,我们可以将main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (length . lines $ str) >>= print
转换为return (length . lines $ str) >>= print
(即“创建一个包含值的容器(这由print (length . lines $ str)
完成),然后将该值传递给return
}只是将值传递给print
“)。同样,我们可以删除括号,所以我们有:
print
看!我们可以执行eta转换:main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> print . length . lines $ str
变为\str -> print . length . lines $ str
。这留下了:
print . length . lines
此时,我们可能会停止,因为该表达式比原始表达式简单得多(如果我们愿意的话,我们可以继续使用>=>
)。由于它更简单,所以它也更容易调试(想象一下,如果我们忘记使用main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>= print . length . lines
:在原始的lines
中它不是很清楚,在最后一个中它是显而易见的。 )
在您的代码中,您可以而且应该这样做:您可以使用sections之类的内容(这意味着main
与\x -> x !! 1
相同),以及eta转换和monad我上面用的法律。