问题描述
我正在尝试实现一个简单的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开始。