您尝试编写一些看起来非常命令式的代码,坦率地说,这有点混乱。如果您尝试像 Java 一样编写 SML 代码,那么,这会很糟糕。
让我们以更实用的风格重做它,而不是尝试修复原始代码。首先,模式匹配。在您的代码中,您使用if-then-else
表达式来检查列表是否为空。相反,我们将使用模式匹配:
fun horner ([] , x) = 0.0
| horner (n::ns, x) = ...
这有两个好处。首先,它为我们拆分了列表 - 我们现在可以使用n
引用列表中的第一项,并且ns
来参考其余的。其次,它更具可读性。
现在我们需要实际的数学。现在,霍纳的方法使用一个变量,您将其称为result
在您的代码中,积累答案。然而,我们主要使用函数式语言进行编码,并避免ref
那就太好了。相反,我们将向该函数添加一个额外的参数。
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