rnso
rnso

Reputation: 24613

Code to copy each element of list to another runs without error but does nothing

I am trying to learn Haskell. In following code, I am trying to copy each element of a list to another through own function and then trying to print new list.

orilist =  ["a", "b", "c"]
mylist = []
addfn ss = do   -- trying to add sent string ss to mylist
    let mylist = ss:mylist
    return ()
main = do 
    mapM_ addfn orilist     -- trying to send each element of orilist to addfn
    mapM_ putStrLn mylist   -- trying to print each element of mylist 
    return ()       -- no error but nothing is printed

The code runs without any error but nothing is printed. Where is the problem? Thanks for your help.

Upvotes: 0

Views: 66

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477437

Your addfn will not do anything, well it only returns a unit (). Indeed, your addfn function:

addfn ss = do   -- trying to add sent string ss to mylist
    let mylist = ss:mylist
    return ()

Is equivalent to:

addfn _ = return ()

since you never use mylist. If you would use mylist, it will be an infinite list that contains [ss, ss, …].

In Haskell there are no assignments: you do not assign a value to a variable, you declare a variable. Once a variable has a value, you can never alter that value. So even if if there was a variable named mylist earlier, it would still not use that variable.

After you used mapM_ addfn orilist, each addfn will have returned (), and have not changed the state of anything, hence the list remains empty.

In your comment, you look to read the first line of each file. You can do that, for example by writing a function that reads the first line of a file:

import System.IO(IOMode(ReadMode), withFile, hGetLine)

readFirstLine :: FilePath -> IO String
readFirstLine fp = withFile fp ReadMode hGetLine

Then we can for example obtain a list of first lines of files with:

main :: IO ()
main = do
    d <- mapM readFirstLine ["foo.txt", "bar.txt"]
    print d

Upvotes: 4

chi
chi

Reputation: 116174

addfn ss = do   -- trying to add sent string ss to mylist
    let mylist = ss:mylist
    return ()

This defined a local binding mylist to be the infinite list ss:ss:ss:.... Then, it's not used, so this definition is irrelevant. Hence, the code is equivalent to:

addfn ss = return ()

which is a no-op.

Haskell is not an imperative language. You are probably trying to modify the global variable mylist, but that's impossible. Once you define mylist = [], it will be [] forever.

You could do this instead:

orilist =  ["a", "b", "c"]

main = do 
    let mylist = orilist
    mapM_ putStrLn mylist   -- trying to print each element of mylist

Or even

orilist =  ["a", "b", "c"]

main = mapM_ putStrLn orilist

Another example: suppose we want to start with an empty list and, for 10 times, reverse it and append its length. We can do this as follows, using recursion:

doOnce oldList = reverse oldList ++ [length oldList]

newList = go 0 []
   where go 10 list = list
         go n list = go (n+1) (reverse list ++ [length list])

This is very inefficient, but I hope but you get the idea.

Upvotes: 3

Related Questions