为什么我不能这样做?它禁止在这个问题中使用'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
Run Code Online (Sandbox Code Playgroud)
[编辑]解决方案:
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
Run Code Online (Sandbox Code Playgroud)
使用return (words y)而不仅仅是words y.return包装了一个纯值(如[String]该words返回)到一个单子.
根据你的措辞,听起来这个问题就是家庭作业.如果是这样,它应该被标记为这样.
(这并没有直接回答这个问题,但它会使你的代码更加惯用,从而更容易阅读.)
您正在使用该模式\x -> f x >>= ...,这可以(并且应该)被消除:它(大多数)是不必要的噪声,它掩盖了代码的含义.我不会使用你的代码,因为它是作业,但考虑这个例子(注意我正在使用return其他答案的建议):
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (lines str) >>=
\lns -> return (length lns) >>=
\num -> print num
Run Code Online (Sandbox Code Playgroud)
(它从用户读取文件名,然后打印该文件中的行数.)
最简单的优化是我们计算行数的部分(这对应于你将单词分开并获得第二行的部分):字符串中的行数str就是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
Run Code Online (Sandbox Code Playgroud)
现在,下一个优化正在进行中\num -> print num.这可以写成公正的print.(这称为eta转换).(您可以将此视为"一个接受参数并调用print它的函数,与它print自身相同").现在我们有:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (length . lines $ str) >>= print
Run Code Online (Sandbox Code Playgroud)
我们可以做的下一个优化是基于monad定律.使用第一个,我们可以return (length . lines $ str) >>= print变成print (length . lines $ str)(即"创建一个包含值的容器(由此完成return)然后传递该值与print将值传递给print")相同.同样,我们可以删除括号,所以我们有:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> print . length . lines $ str
Run Code Online (Sandbox Code Playgroud)
看!我们可以进行eta转换:\str -> print . length . lines $ str变得公正print . length . lines.这留下:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>= print . length . lines
Run Code Online (Sandbox Code Playgroud)
在这一点上,我们可能会停止,因为那个表达式比我们原来的表达式简单得多(我们可以继续使用,>=>如果我们想要的话).因为它更简单,所以它也更容易调试(想象一下,如果我们忘记使用它们lines:原来main它不是很清楚,在最后一个很明显.)
在你的代码中,你可以而且应该这样做:你可以使用诸如section之类的东西(这意味着\x -> x !! 1相同(!! 1)),以及我在上面使用的eta转换和monad定律.
| 归档时间: |
|
| 查看次数: |
542 次 |
| 最近记录: |