在Haskell中使用IO时,难以将元素附加到列表中

时间:2012-02-05 08:49:26

标签: list haskell io

我有一个整数列表,我需要在不同的时间将元素附加到它。

let xs =[]::[Int]

通常将元素添加到此类似:

1:xs

但是在函数中使用IO时,它似乎不在do块中工作并且会出错,并且

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

产生无限列表,如[1,2,2,2,2,.....] 我该怎么做才能纠正这个问题?

4 个答案:

答案 0 :(得分:7)

您似乎对Haskell中的列表存在根本性的误解。列表始终是不可变的,因此无法将新元素添加到现有列表中。即您只能创建新列表。

因此,a:b运算符从不向列表添加元素,而是创建一个新列表,其中a是第一个元素,后面是现有列表b

当你说:

let xs = 2 : xs

你是说xs是一个列表,其中第一个元素是2,列表的其余部分是xs本身,这在逻辑上会导致2的无限列表。在这个问题的背景下,你是否在IO monad中无关紧要。

因此,鉴于上述情况,您需要执行类似

的操作
let xs1 = [1]
let xs2 = 2:xs1
let xs3 = 3:xs2

但当然,这与简单地做

相同
let xs3 = [3,2,1]

所以你真的需要提供一些关于你想要建立什么类型的列表以及原因的更多背景信息。

答案 1 :(得分:5)

在Haskell中,let绑定默认是递归的。所以第二行中的两个xs指的是自己。解决方案是影响xs绑定:

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

请记住,Haskell不允许变异。因此第二个let绑定意味着更改xs的值 - 这意味着创建一个恰好也称为xs的新变量。< / p>

只是澄清一下:xs'xs完全分开。 Haskell允许您在变量名中使用'xs'这里可以很容易xs2'发音为“prime”(例如exes prime),并取自数学,其中xx'x''之类的内容很常见。

附注:: 预先到列表中;追加意味着将元素放在最后。

此外,您的let xs = 2:xs会产生[2,2,2...]而不是[1,2,2,2...]

答案 2 :(得分:2)

为了完整性,如果确实想要在IO monad中强制“分配”(这是你似乎得到的),你可以。您将使用可变单元格(“参考”); IO monad中的IORef

import Data.IORef

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

然而,这样做会非常单一,你几乎不想写这样的东西。

答案 3 :(得分:0)

不要让你的列表递归吗?

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