Functional programming 标准ML:计算给定集合的平均值
我最近的任务是用标准ML计算一个集合(由输入给出)的平均值 其想法是使用如下函数,在该函数中,您输入实数列表并接收这些数字的平均值(也是实数),以便终端在您输入函数时将其作为返回答案:Functional programming 标准ML:计算给定集合的平均值,functional-programming,average,sml,Functional Programming,Average,Sml,我最近的任务是用标准ML计算一个集合(由输入给出)的平均值 其想法是使用如下函数,在该函数中,您输入实数列表并接收这些数字的平均值(也是实数),以便终端在您输入函数时将其作为返回答案: average = fn : real list -> real 我们在教程中也讨论了这一点,但我想知道在标准ML中创建此类函数时是否有一些技巧 提前谢谢 将数字相加,然后除以长度。简单的递归求和通常是您在任何SML教程中看到的第一个示例之一。您需要将空列表基本情况下的sum计算为0.0,而不是0,以确保
average = fn : real list -> real
我们在教程中也讨论了这一点,但我想知道在标准ML中创建此类函数时是否有一些技巧
提前谢谢 将数字相加,然后除以长度。简单的递归
求和
通常是您在任何SML教程中看到的第一个示例之一。您需要将空列表基本情况下的sum
计算为0.0
,而不是0
,以确保返回类型为real
。一旦定义了一个sum
函数,就可以使用sum
和内置的length
函数在一行中定义average
。一个微妙之处是SML不允许将实数除以整数。在将总和除以整数之前,可以对长度使用转换函数real.fromInt
。将同一个列表传递两次,一次求和,一次计算长度,会有一些低效,但是当你第一次学习语言时,没有理由担心这些事情
关于编辑:由于您已经找到了一个自然的解决方案,并在评论中分享了它,下面是一个更为惯用的版本,它计算列表中一次通过的平均值:
fun average nums =
let
fun av (s,n,[]) = s/Real.fromInt(n)
| av (s,n,x::xs) = av (s+x,n+1,xs)
in
av (0.0, 0, nums)
end;
它通过定义一个辅助函数来完成繁重的工作。这些在函数式编程中被广泛使用。在没有可变状态的情况下,一个常见的技巧是显式地将数量作为参数传递,这些数量将由命令式语言中的相应循环依次修改。此类参数通常称为
累加器
,因为它们通常累加增长列表、运行总和、运行乘积等。此处s
和n
为累加器,其中s
为元素之和n
为列表长度。在(s,n,[])
的基本情况下,没有更多可累积的内容,因此返回最终答案。在非基准情况下,(s,n,x::xs)
、s
和n
会被适当修改,并随列表的尾部一起传递给helper函数。因此,av
的定义将以循环的速度运行,而不会增加堆栈。整体average
函数需要做的唯一一件事就是使用适当的初始值调用helper函数。让。。。助手定义。。。在里面用启动值调用helper…end
是一种常用的习惯用法,用于防止程序的顶层被helper函数弄得乱七八糟。由于只有非空列表才能有平均值,John Coleman的另一个答案是:
fun average [] = NONE
| average nums =
let
fun av (s,n,[]) = s/Real.fromInt(n)
| av (s,n,x::xs) = av (s+x,n+1,xs)
in
SOME (av (0.0, 0, nums))
end;
计算平均值的函数是否应该考虑非空列表取决于您是打算导出它,还是只在您在其他地方保证输入列表非空的范围内使用它。a+用于向学生提供指导/解释,而不是仅仅给出一个没有教什么的答案。@john谢谢你的帮助!在本教程中,我们讨论了如何使用几个函数来实现这一点。我们不应该使用任何内置库(即Real.fromInt)。所以我尝试了多函数方法,得到了如下结果(有效):sum函数:
fun sum(h::t)=h+sum(t)| sum(nil)=0.0代码>长度函数:fun length(h::t)=1.0+长度(t)| length(nil)=0.0代码>完整函数:fun平均值(l)=总和(l)/长度(l)代码>@opheliaxo Nice。我发现将基本情况放在递归情况之前稍微自然一些,但这主要是一个品味问题,也许是惯例问题。因为我不必再担心别人的家庭作业,在他们有兴趣自己解决之前,我编辑了我的答案,包括我认为最惯用、最有效的计算SML平均值的方法。