我正在尝试在SML中实现Horner's algorithm。
fun horner(lst1:real list,x:real) =
let
val i = ref 1
val result = ref (List.last(lst1))
in
if (lst1) = ([]:real list) then 0.0
else
while (!i <= length(lst1)-1) do
(result:=!result*x+List.nth(lst1,length(lst1)-(!i)-1);
i := !i+1);
!result
end;
接受{n},x ^ n的系数作为其初始结果,然后使用horner评估多项式。
评估为((a {n} * x + a {n-1})* x + a {n-2})..列表包含多项式的系数。 问题是“if lst1 = [] .... else”部分。 仅使用while循环使程序运行良好。 但我想不出那个部分有什么问题。
答案 0 :(得分:3)
你已经尝试过编写一些非常具有命令性的代码,坦率地说,这有点乱。如果你试图将你的SML代码编写为Java,那么,这会受到伤害。
不要试图修复原始代码,而是让它以更实用的方式重做。首先,模式匹配。在代码中,使用if-then-else
表达式检查列表是否为空。相反,我们将使用模式匹配:
fun horner ([] , x) = 0.0
| horner (n::ns, x) = ...
这有两个好处。首先,它会为我们分割列表 - 我们现在可以使用n
来引用列表中的第一项,并使用ns
来引用其余项。其次,它更具可读性。
现在我们需要实际的数学。现在,horner的方法使用一个变量,你在代码中调用了result
来积累答案。但是,我们使用的函数主要是函数式语言,避免ref
s会很好。相反,我们将在函数中添加一个额外的参数。
fun horner ([] , x, acc) = acc
| horner (n::ns, x, acc) = ...
当然,我们希望函数只能使用两个参数,因此我们将数学放在辅助函数中,并使实函数调用辅助函数:
fun horner' ([] , x, acc) = acc
| horner' (n::ns, x, acc) = ...
fun horner (xs, x) = horner' (xs, x, 0.0)
这是在函数式编程中看到的相当常见的模式,而SML具有隐藏辅助函数的工具,因此我们不会混淆全局命名空间。例如,我们可以将辅助函数放在let
- 表达式中:
fun horner (xs, x) = let
fun horner' ([] , x, acc) = acc
| horner' (n::ns, x, acc) = ...
in
horner' (xs, x, 0.0)
end
最后,我们添加了horner'
的递归调用。
fun horner (xs, x) = let
fun horner' ([] , x, acc) = acc
| horner' (n::ns, x, acc) = horner' (ns, x, n + x * acc)
in
horner' (xs, x, 0.0)
end
以下是我们调用horner
函数时会发生的事情:
horner ([3.0, 2.0, 4.0], 2.0) ~> horner' ([3.0, 2.0, 4.0], 2.0, 0.0)
~> horner' ([2.0, 4.0] , 2.0, 3.0 + 2.0 * 0.0)
~> horner' ([2.0, 4.0] , 2.0, 3.0)
~> horner' ([4.0] , 2.0, 2.0 + 2.0 * 3.0)
~> horner' ([4.0] , 2.0, 8.0)
~> horner' ([] , 2.0, 4.0 + 2.0 * 8.0)
~> horner' ([] , 2.0, 20.0)
~> 20.0