刚开始学习 SML:如何取两个整数和 return 之间所有整数的列表
Just Started Learning SML: How to take two ints and return the list of all ints between
标题说的差不多。我刚开始学习 SML,但在我的第一个项目中遇到了问题。我知道这是一个非常基本的问题,对我来说,用 java 之类的东西做起来会非常容易,但我很难理解 SML。我需要写一个函数 intsFromTo。它应该取一对整数,low 和 high,以及 return 一个按升序排列的连续整数列表,即所有大于或等于 low 且小于或等于 high 的整数。
这是我目前所拥有的
fun intsFromTo (low,high) = val intList = []
if low >= high then nill
else intList::low intsFromTo(low+1,high);
我遇到了以下错误,我也很难理解。
http://i.imgur.com/QZ0WT6j.png
任何帮助我前进的人都将不胜感激。
你的代码有几个问题,只要把隐藏的部分揭开就能看到答案,不过我只是先提示一下,帮助你自己解决。
- 函数体的语法是什么?
回想一下,函数体在定义局部值时需要 let ... in ... end
,就像您在 intList
:
中所做的那样
- 价值是多少
nill
?
你的意思可能是 nil
,或者 []
- 你想用
intList::low intsFromTo(low+1,high)
表达什么?
您几乎说对了:您的目标是 return 由当前 low
元素组成的列表,然后是从其后继元素到最高元素的列表。这是写成:low :: intsFromTo (low+1,high)
。详细解释:你实际上并排写了 2 个不同的表达式(intList::low
和对 intsFromTo
的递归调用),第一个不是函数,所以它不能应用于第二个(记住这与 lambda 演算中的原理相同)。
然后呢?
经过这些更改后,生成的程序应该可以编译,但它的实现可以改进(提示:intList
?)。这留作 reader.
的练习
注意:代码的风格可能更紧凑,但可能无法清楚地说明基本概念。
典型递归
fun intsFromTo(low, high) =
let
val out = []
in
if
low <= high
then
low :: intsFromTo2(low + 1, high)
else
out
end
替代方法
生成列表的另一种方法是在列表上使用 map-reduce
样式语义。
fun intsFromTo(low, high) =
if high > low
then (* the list will contain at least one value *)
if
high >= 0
then
List.tabulate((high + 1) - low,
fn k => k + low)
else
List.rev(
List.tabulate((~low + 1) + high,
fn k => ~k + high))
else
[] (* list empty: low >= high *)
为什么选择替代方案?
只是出于好奇。
性能
轶事计时表明第一个版本的速度大约是第二个版本的两倍:
fun time() =
let
val t = Timer.startCPUTimer();
in
intsFromTo(~1000000,1000000);
Time.toReal(#usr(Timer.checkCPUTimer(t)))
end
至少在我的电脑上,当它被用于其他事情时。
迟到的答案,但这里有一个可爱的紧凑递归定义。
fun intList a b = if (a = b) then [b]
else a::intList (a+1) b;
标题说的差不多。我刚开始学习 SML,但在我的第一个项目中遇到了问题。我知道这是一个非常基本的问题,对我来说,用 java 之类的东西做起来会非常容易,但我很难理解 SML。我需要写一个函数 intsFromTo。它应该取一对整数,low 和 high,以及 return 一个按升序排列的连续整数列表,即所有大于或等于 low 且小于或等于 high 的整数。
这是我目前所拥有的
fun intsFromTo (low,high) = val intList = []
if low >= high then nill
else intList::low intsFromTo(low+1,high);
我遇到了以下错误,我也很难理解。
http://i.imgur.com/QZ0WT6j.png
任何帮助我前进的人都将不胜感激。
你的代码有几个问题,只要把隐藏的部分揭开就能看到答案,不过我只是先提示一下,帮助你自己解决。
- 函数体的语法是什么?
回想一下,函数体在定义局部值时需要
中所做的那样let ... in ... end
,就像您在intList
:
- 价值是多少
nill
?
你的意思可能是
nil
,或者[]
- 你想用
intList::low intsFromTo(low+1,high)
表达什么?
您几乎说对了:您的目标是 return 由当前
low
元素组成的列表,然后是从其后继元素到最高元素的列表。这是写成:low :: intsFromTo (low+1,high)
。详细解释:你实际上并排写了 2 个不同的表达式(intList::low
和对intsFromTo
的递归调用),第一个不是函数,所以它不能应用于第二个(记住这与 lambda 演算中的原理相同)。
然后呢?
经过这些更改后,生成的程序应该可以编译,但它的实现可以改进(提示:
的练习intList
?)。这留作 reader.
注意:代码的风格可能更紧凑,但可能无法清楚地说明基本概念。
典型递归
fun intsFromTo(low, high) =
let
val out = []
in
if
low <= high
then
low :: intsFromTo2(low + 1, high)
else
out
end
替代方法
生成列表的另一种方法是在列表上使用 map-reduce
样式语义。
fun intsFromTo(low, high) =
if high > low
then (* the list will contain at least one value *)
if
high >= 0
then
List.tabulate((high + 1) - low,
fn k => k + low)
else
List.rev(
List.tabulate((~low + 1) + high,
fn k => ~k + high))
else
[] (* list empty: low >= high *)
为什么选择替代方案? 只是出于好奇。
性能
轶事计时表明第一个版本的速度大约是第二个版本的两倍:
fun time() =
let
val t = Timer.startCPUTimer();
in
intsFromTo(~1000000,1000000);
Time.toReal(#usr(Timer.checkCPUTimer(t)))
end
至少在我的电脑上,当它被用于其他事情时。
迟到的答案,但这里有一个可爱的紧凑递归定义。
fun intList a b = if (a = b) then [b]
else a::intList (a+1) b;