Fly*_*man 2 io monads haskell loops
我想从列表中删除一个项目,但它又回来了。
main = do
let y = ["aa","bb","cc","dd","ee","ff"]
let n = length y
replicateM_ (n-1) (deleteWord y)
deleteWord y = do
putStrLn "Write a word: "
word <- getLine
let new_y = delete word y
print new_y
Run Code Online (Sandbox Code Playgroud)
输出:
*Main> main
Write a word:
aa
["bb","cc","dd","ee","ff"]
Write a word:
bb
["aa","cc","dd","ee","ff"]
Write a word:
cc
["aa","bb","dd","ee","ff"]
Run Code Online (Sandbox Code Playgroud)
我希望 和"aa"保持"bb"删除状态,并且不再回到列表中。
正如评论中所解释的,该y值一旦定义,就像 Haskell 中的每个值一样是不可变的。
但是有一个单子库函数,nest :: Monad m => Int -> (a -> ma) -> a -> ma,它允许您将一个动作的结果重新注入到同一个动作中,例如一些次。
\n为了使用它,您的基本操作需要返回一个结果:
\n$ ghci\nGHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help\n...\n \xce\xbb>\n \xce\xbb> import Data.List(delete)\n \xce\xbb> import Control.Monad.HT(nest)\n \xce\xbb> \n \xce\xbb> \n \xce\xbb> :{\n|\xce\xbb> deleteWord y = do\n|\xce\xbb> putStrLn "Write a word: "\n|\xce\xbb> word <- getLine\n|\xce\xbb> let new_y = delete word y\n|\xce\xbb> print new_y\n|\xce\xbb> return new_y -- HERE !!!\n|\xce\xbb> :}\n \xce\xbb> \n \xce\xbb> :type deleteWord\n deleteWord :: [String] -> IO [String]\n \xce\xbb> \n \xce\xbb> action3 = nest 3 deleteWord\n \xce\xbb> \n \xce\xbb> :type action3\n action3 :: [String] -> IO [String]\n \xce\xbb> \nRun Code Online (Sandbox Code Playgroud)\n那么让我们尝试运行该嵌套操作:
\n \xce\xbb> \n \xce\xbb> res3 <- action3 ["aa","bb","cc","dd","ee","ff"]\nWrite a word: \nff\n["aa","bb","cc","dd","ee"]\nWrite a word: \naa\n["bb","cc","dd","ee"]\nWrite a word: \ndd\n["bb","cc","ee"]\n \xce\xbb> \n \xce\xbb>\n \xce\xbb> res3\n["bb","cc","ee"]\n \xce\xbb> \nRun Code Online (Sandbox Code Playgroud)\n对于刚开始的 Haskell 程序员来说,源代码nest可能并不完全具有启发性。但库源代码的主要目标是最大限度地提高运行时效率。
可以编写一个更简单的版本,并明确递归:
\nmyNest :: Monad m => Int -> (a -> m a) -> a -> m a\nmyNest n fn a0 =\n if (n <= 0) then (return a0)\n else do\n a1 <- fn a0\n myNest (n-1) fn a1\nRun Code Online (Sandbox Code Playgroud)\n