Haskell:将整数压入堆栈实现时的无限列表

问题描述

我正在尝试实现一个简单的Stack,但是对于为什么在将整数压入堆栈时会得到一个无限列表感到困惑。

所有其他功能都按预期运行,但我不了解 @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Weather App',theme: ThemeData( primarySwatch: Colors.blue,),home: Scaffold( backgroundColor: Colors.tealAccent,appBar: AppBar( title: Text('Flutter Weather App'),body: Container( height: 501.7,width: 420.0,decoration: Boxdecoration( image: decorationImage( image: isweatherDataLoaded //this ? HandleError() : images["clear"],fit: BoxFit.fill,shape: BoxShape.rectangle,child: Center( child: Column(children: <Widget>[ //WEATHER DATA Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[ Padding( padding: const EdgeInsets.all(8.0),child: weatherData != null ? Weather(weather: weatherData) : Container(),Padding( padding: const EdgeInsets.all(8.0),child: isLoading ? CircularProgressIndicator( strokeWidth: 2.0,valueColor: new AlwaysstoppedAnimation(Colors.black),) : IconButton( icon: new Icon(Icons.refresh),tooltip: 'Refresh',onpressed: () async { await loadWeather(); },color: Colors.black,],//FUTURE FORECAST WEATHER DATA SafeArea( child: Padding( padding: const EdgeInsets.all(8.0),child: Container( height: 200.0,child: forecastData != null ? ListView.builder( itemCount: forecastData.list.length,scrollDirection: Axis.horizontal,itemBuilder: (context,index) => WeatherItem( weather: forecastData.list.elementAt(index))) : Container(),) ])),)),); } 的问题。当我尝试为其分配一个已推送如下变量的空堆栈时,它出错了:

push
λ > a = makeStack
λ > push 3 a
[3]
λ > a
[]
λ > a = push 3 a
λ > a
[3,3,3^CInterrupted.

解决方法

Haskell不允许突变。在源文件中,如果您定义一个变量a,然后尝试重新分配它,就像在此处使用a = push 3 a一样,则会出现编译错误。不这样做的唯一原因是您正在使用GHCi,它确实允许您重新定义变量-这纯粹是一种方便,因此您在尝试不同的定义时不必继续思考新的名称。

而且,至关重要的是,a = push 3 a不是 ,它以命令式语言为基础,给a赋予了新的价值。相反,它是a 本身的定义

这就是为什么您获得无限列表的原因-您的定义按以下方式处理:

a = push 3 a
   = 3:a
   = 3:(push 3 a)
   = 3:(3:a)

,依此类推。由于Haskell的懒惰,像这样的定义没有问题-当您要求完整列表时,GHCi会像这样在此处每次只计算一个元素,因此继续打印3s直到告诉它停止。>

要获得所需的内容,您只需键入push 3 a,或者如果需要为其指定名称,只需从a中选择一个不同的名称即可。 b = push 3 a后跟b的行为将符合您的预期。

,

haskell中几乎没有(我想几乎是)可变的变量(感谢@amalloy来纠正我的术语)。

如果您编写这样的内容:

x = f x

它进入无限循环:f (f (f ...

因此,没有a past 值可以推入3

因此,您必须将push 3 a设置为其他值(或者直接放入ghci)。

这种循环有时可能会派上用场。看看Data.Function.fix

fix :: (a -> a) -> a
fix f = let x = f x in x

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

GHCi> fix (push 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,我想邀请他们进行漫长而有趣的旅行。我建议他们从此wikibook on denotational semantics开始。