【发布时间】:2012-02-05 08:49:25
【问题描述】:
我有一个整数列表,我需要在不同的时间向它附加元素。
let xs =[]::[Int]
通常在此附加元素会是这样的:
1:xs
但是在函数中使用 IO 时,它似乎在 do 块中不起作用并给出错误,并且
let xs = [1]
let xs=(2:xs)
产生一个无限列表,如 [1,2,2,2,2,.....] 我能做些什么来纠正这个问题?
【问题讨论】:
我有一个整数列表,我需要在不同的时间向它附加元素。
let xs =[]::[Int]
通常在此附加元素会是这样的:
1:xs
但是在函数中使用 IO 时,它似乎在 do 块中不起作用并给出错误,并且
let xs = [1]
let xs=(2:xs)
产生一个无限列表,如 [1,2,2,2,2,.....] 我能做些什么来纠正这个问题?
【问题讨论】:
您似乎对 Haskell 中的列表存在根本性的误解。列表始终是不可变的,因此无法将新元素添加到现有列表中。 IE。您只能创建新列表。
因此,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]
因此,您确实需要提供更多背景信息,说明您想要构建什么样的列表以及原因。
【讨论】:
在 Haskell 中,let 绑定默认是递归的。所以第二行中的两个xs 指的是他们自己。解决方案是不隐藏xs 绑定:
let xs = [1]
let xs' = 2:xs
请记住,Haskell 不允许突变。所以第二个let 绑定并不意味着改变xs 的值——它意味着创建一个新变量,它恰好也被称为xs。
澄清一下:xs' 与 xs 完全分开。 Haskell 允许你在变量名中使用'。 xs' 这里很容易成为xs2。 ' 发音为“prime”(例如 exes prime),取自 x、x' 和 x'' 等常见的数学。
附注:: 添加到列表中; appending 表示将元素放在末尾。
此外,您的 let xs = 2:xs 会生成 [2,2,2...] 而不是 [1,2,2,2...]。
【讨论】:
xs',这是将2 附加到xs 的结果。从那时起,只需使用xs' 而不是xs。如果不是递归的let 绑定,你的代码会做同样的事情,除了xs' 将被称为xs。
let xs = [1] , let xs' = 2:xs , let xs' = 3:xs 时,这 3 行 xs 只会输出 [3,1],2 不会被前置
let 时,您都在创建一个new 变量,而不是更改以前的变量。 Haskell 允许这个新变量与旧变量具有相同的名称(阴影),但您不应该这样做。如果您真的必须有这样的单独步骤,请为每个列表命名不同的名称。
为了完整起见,如果您真的想要在 IO monad 中强制“分配”(这就是您的意思),您可以。您将使用可变单元格(“参考”);在 IO monad 中,将是 IORef:
import Data.IORef
do xs <- newIORef [1]
temp <- readIORef xs
writeIORef xs (2 : temp)
但是,这样做会非常不习惯,而且你几乎不想写这样的东西。
【讨论】:
不要让你的列表是递归的吗?
let xs = [1]
let foo=(2:xs) -- non-recursive
【讨论】: