Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell:将整数推送到堆栈实现时的无限列表_Haskell_Stack - Fatal编程技术网

Haskell:将整数推送到堆栈实现时的无限列表

Haskell:将整数推送到堆栈实现时的无限列表,haskell,stack,Haskell,Stack,我试图实现一个简单的堆栈,但我不明白为什么在将整数推入堆栈时会得到一个无限列表 所有其他函数都按照我的预期工作,但我不理解push的问题。当我尝试将一个空堆栈分配给它自己时出错,该堆栈推送了一个变量,如下所示: λ > a = makeStack λ > push 3 a [3] λ > a [] λ > a = push 3 a λ > a [3,3,3,3,3,3,3,3,3,3^CInterrupted. haskell中(我猜,几乎)没有可变的变量(多亏@

我试图实现一个简单的堆栈,但我不明白为什么在将整数推入堆栈时会得到一个无限列表

所有其他函数都按照我的预期工作,但我不理解
push
的问题。当我尝试将一个空堆栈分配给它自己时出错,该堆栈推送了一个变量,如下所示:

λ > a = makeStack
λ > push 3 a
[3]
λ > a
[]
λ > a = push 3 a
λ > a
[3,3,3,3,3,3,3,3,3,3^CInterrupted.
haskell中(我猜,几乎)没有可变的变量(多亏@amalloy纠正了我的术语)

如果你这样写:

x = f x
它进入一个无限循环:
f(f(f…

因此,
a
的过去值不存在,其中可以推送
3

因此,您必须将
push 3A
放入其他值中(或直接放入ghci)

不过,这样的循环有时可能会派上用场。请看:

它可以用来做与您相同的事情:

GHCi> fix (push 3)
[3,3,3,3,^CInterrupted.
然而,无限循环并不总是如此。看看:

factFun rec n = if n == 0 then 1 else n * rec (n - 1)
此函数可能看起来像阶乘,但非终止分支中的递归调用被替换为伪(
rec
)。我们希望将此伪函数反复替换为
factFun
,以获得阶乘。
fix
执行以下操作:

GHCi> fix factFun 4
24


注意:我将在这里重复我的评论:如果读者还不知道
fix
,我想邀请他们进行一次漫长而有趣的旅行。我建议他们从这个开始。

Haskell不允许变异。在源文件中,如果您定义变量
a
,然后尝试重新分配它,就像您在这里对
a=push 3所做的那样一个
,你会得到一个编译错误。你不这样做的唯一原因是你在GHCi中工作,它允许你重新定义变量-这纯粹是一种方便,所以你不必在尝试不同的定义时不断想出新的名称

而且,至关重要的是,
a=push 3 a
并没有在前一个值的基础上给
a
赋予新的值,就像在命令式语言中那样。相反,它是
a
本身的定义

这就是为什么您会得到一个无限列表-您的定义处理如下:

a = push 3 a
   = 3:a
   = 3:(push 3 a)
   = 3:(3:a)
等等。由于Haskell的懒惰,像这样的定义没有问题-当你要求完整的列表时,GHCi会像这里一样,一次只计算一个元素,因此一直打印3,直到你告诉它停止为止


要想得到你想要的,你需要输入
push 3a
,或者如果你需要为它指定一个名称,只需从
a
中选择一个不同的名称
b=push 3a
,然后是
b
,它将按照你的预期运行。

这是一个非常有趣的函数!我要看看我是否可以使用它!@JiangShiion.我建议你去看看-它说明了很多。这就是我开始的地方。祝你好运:)。Haskell中有很多变量。它们是不可变的。@amalloy你是对的-对不起我的术语。我编辑了这篇文章。我记得在GHCi(或者任何
do
块)中有一个特殊的“重新分配”技巧一个使用自身的变量:
a Yes,它将在
do
块中工作(如果您对其进行去语法化,左边的“new”
a
是lambda的参数,因此会将“old”参数隐藏起来),但必须理解这与正常的“赋值”(或者更确切地说是定义)非常不同在Haskell中。我不确定GHCi是否允许这样做,并且必须尝试一下——我知道GHCi隐式地将所有事情解释为发生在
IO
monad中,但如果它允许一行带有“左箭头”,我会感到惊讶我提到这个技巧只是因为我看到其他人推荐它,因为
do
中的绑定默认是非递归的(使用
do rec
显式递归)。(作者认为
let
默认是递归的在Haskell中是不幸的。)我个人认为,一个“左箭头”绑定在GHCi中应该是有效的,这并不奇怪,否则就无法获得IO操作的中间结果,并将其绑定到变量以供进一步使用。
GHCi> fix factFun 4
24
a = push 3 a
   = 3:a
   = 3:(push 3 a)
   = 3:(3:a)