Home > Net >  Removed item from a list comes back
Removed item from a list comes back

Time:02-14

I want to remove an item from a list, but it comes back.

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

OUTPUT= 

*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"]

I want that the "aa" and "bb" stay removed and not come back into the list.

CodePudding user response:

As explained in the comments, the y value, once defined, is immutable like every value in Haskell.

But there is a monadic library function, nest :: Monad m => Int -> (a -> m a) -> a -> m a, that allows you to re-inject the result of an action into that very same action, for some number of times.

In order to use it, your base action needs to return a result:

$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/  :? for help
...
 λ>
 λ> import Data.List(delete)
 λ> import Control.Monad.HT(nest)
 λ> 
 λ> 
 λ> :{
|λ> deleteWord y = do
|λ>   putStrLn "Write a word: "
|λ>   word <- getLine
|λ>   let new_y = delete word y
|λ>   print new_y
|λ>   return new_y  -- HERE !!!
|λ> :}
 λ> 
 λ> :type deleteWord
 deleteWord :: [String] -> IO [String]
 λ> 
 λ> action3 = nest 3 deleteWord
 λ> 
 λ> :type action3
 action3 :: [String] -> IO [String]
 λ> 

So let's try to run that nested action:

 λ> 
 λ> res3 <- action3 ["aa","bb","cc","dd","ee","ff"]
Write a word: 
ff
["aa","bb","cc","dd","ee"]
Write a word: 
aa
["bb","cc","dd","ee"]
Write a word: 
dd
["bb","cc","ee"]
 λ> 
 λ>
 λ> res3
["bb","cc","ee"]
 λ> 

Addendum:

The source code for nest is perhaps not exactly illuminating for a beginning Haskell programmer. But the primary goal for library source code is to maximize runtime efficiency.

It is possible to write a simpler version with recursion made explicit:

myNest :: Monad m => Int -> (a -> m a) -> a -> m a
myNest n fn a0 =
    if (n <= 0) then  (return a0)
                else  do
                          a1 <- fn a0
                          myNest (n-1) fn a1

CodePudding user response:

Coded with direct recursion; with minimal changes to your code:

main = do
  let y = ["aa","bb","cc","dd","ee","ff"]
  let n = length y
  -- replicateM_ (n-1) (deleteWord y)
  deleteWord n y

deleteWord k y | k <= 0 = return ()
deleteWord k y = do      --<<----<<---.
  putStrLn "Write a word: "        -- |
  word <- getLine                  -- |
  let new_y = delete word y        -- |
  print new_y                      -- |
  deleteWord (k-1) new_y      --->>---'

using the updated value, new_y, in the recursive invocation.

  • Related