简体   繁体   中英

Difficulty in appending elements to a list when using IO in Haskell

I have a list of integers, I need to append elements to it at different times.

let xs =[]::[Int]

usually appending elements to this would be like:

1:xs

but when using IO in a function, it doesn't seem to work within a do block and gives errors, and

let xs = [1]
let xs=(2:xs)

results in an infinite list like [1,2,2,2,2,.....] What can I do to correct this?

You seem to have a fundamental misunderstanding about lists in Haskell. The lists are always immutable, so there is no way to add new elements to an existing list. Ie You can only create new lists.

So, accordingly, the a:b operator never adds an element to a list, but creates a new list where a is the first element, which is followed by the existing list b .

When you say:

let xs = 2 : xs

You are saying that xs is a list where the first element is 2 and the rest of the list is xs itself, which logically results in an infinite list of 2's. In the context of this question, it's irrelevant whether you are in the IO monad or not.

So given the above, you need to do something like

let xs1 = [1]
let xs2 = 2:xs1
let xs3 = 3:xs2

But of course, this is the same as simply doing

let xs3 = [3,2,1]

So you really need to give some more context on what kind of list you want to build and why.

In Haskell, let bindings are recursive by default. So the two xs in the second line refer to themselves. The solution is to not shadow the xs binding:

let xs = [1]
let xs' = 2:xs

Remember that Haskell does not allow mutation. So the second let binding does not mean changing the value of xs --it means creating a new variable that just also happens to be called xs .

Just to clarify: xs' is completely separate from xs . Haskell lets you use ' in variable names. xs' here could as easily be xs2 . The ' is pronounced "prime" (eg exes prime) and taken from math where things like x , x' and x'' are common.

A side note: : prepends to a list; appending means putting the element on the end.

Also, your let xs = 2:xs results in [2,2,2...] rather than [1,2,2,2...] .

For completeness, if you really want to "assign" imperatively in the IO monad (which is what you seemed to be getting at), you could. You would use a mutable cell (a "reference"); which in the IO monad, would be IORef :

import Data.IORef

do xs <- newIORef [1]
   temp <- readIORef xs
   writeIORef xs (2 : temp)

However, doing so would be highly unidiomatic and you almost never want to write stuff like this.

Don't make your list be recursive?

let xs = [1]
let foo=(2:xs) -- non-recursive

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM