我正在编写一个程序,它接受
int
列表并返回它们的交替和的值。
Input: [1,2,3,4]
Output: 1 + (-2) + 3 + (-4)
下面是我尝试为此编写的代码,但我不断收到错误
syntax error: inserting ORELSE
我的
if then else
声明看起来正确,所以我不确定是什么导致了错误
fun alternate([]) = 0
| alternate(x::xs, count) =
count = count + 1
if count mod 2 == 0 then (~x) + alternate(xs)
else x + alternate(xs)
此错误是由于
count = count + 1
和 if ... else ...
是多个表达式导致的。如果要执行多个表达式,可以这样写代码:
(expression1;
expression2;
...
expressionN);
您的代码中还有另外两个错误。
1. 函数不同模式子句中的参数类型不同
alternate
。=
表示相等,而不是 ==
。
所以正确的解决方案可能如下所示:
fun alternate([]) = 0
| alternate(x::xs) =
let
fun alt([], count) = 0
| alt(x::xs, count) =
if count mod 2 = 0 then x + alt(xs, count+1)
else (~x) + alt(xs, count+1)
in
alt(x::xs, 0)
end;
基于我之前的答案,我建议实施sum
:
val sum = foldr (op +) 0;
为了完整起见,从此处复制该答案中的
alternate
函数,并修复一个小错误:
fun alternate l =
let
fun alternate1 [] = []
| alternate1 (x::xs) = x :: alternate2 xs
and alternate2 [] = []
| alternate2 (x::xs) = (~x) :: alternate1 xs
in
alternate1 l
end
然后你可以非常简单地定义
alternate_sum
:
val alternate_sum = sum o alternate
当然会有以表演为名的反对意见。 Haskell 能够跨这些类型的调用执行森林砍伐/融合优化,因为它了解函数的纯度;标准机器学习并不
需要这些优化,尽管有些实现可能会尝试它们,我不知道。
这个特定问题的开销可能荒谬,也可能不荒谬,但我认为无论如何,它都是函数式编程原理的一个很好的例子:从更简单、无可挑剔的行为构建复杂的行为。这个版本的“举证责任”几乎全在alternate
。 @SunsetRider 的版本很好(它可能会表现得更好),但你可能会说代码更加“单一”。另外,@SunsetRider 的代码比需要的要复杂一点,这个版本就足够了:
fun alternate l =
let
fun alt([], count) = 0
| alt(x::xs, count) =
if count mod 2 = 0 then x + alt(xs, count+1)
else (~x) + alt(xs, count+1)
in
alt(l, 0)
end
除了 @SunsetRider 所说的之外,还有一条评论:一般来说,在函数式语言中
x = x + 1
和其他突变有点代码味道。您可以看到,在他们的代码中,他们多次使用
count+1
。从功能上思考,重要的是表达式的计算结果,而不是变量的状态,因此传递的值至关重要。这可以追溯到Pieter HartelFunctional C这本优秀且被严重低估的书开头的superb定义: 函数式和命令式范式从不同的角度运作。函数范式基于“表达式求值”以及将变量绑定到值。基本的程序短语是表达式,计算表达式的目的是产生一个值。子表达式的求值顺序不会影响结果值。
命令式范例基于“语句的执行”并拥有一个存储,语句可以在其中留下其结果。基本的程序短语是语句;执行语句的目的是改变存储。语句执行的顺序确实会影响存储中的结果值。存储中当前的一组值称为程序的
state。 这里有替代解决方案
altSum :: (Num a) => [a] -> a altSum (x:[]) = x altSum (x:y:xs) = x - y + altSum xs
`altsum n = x1 -x2 +x3 -x4 +... +xn = x1 -(x2 -x3 +x4 +...+xn) = x1 - altsum(n-1)
有趣的altsum [] = 0 |代数 x::xs = x - 代数 xs`