I am trying to implement Horner's algorithm in SML.
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;
Takes on a{n}, the coeff of x^n, as its initial result, then using horner's evaluates a polynomial.
Evaluates as ((a{n}*x+a{n-1})*x+a{n-2})..The list contains the coefficients of the polynomial. Problem is the "if lst1 = []....else" part. Employing only the while loop makes the program run well. But I can't think of anything that is wrong with that part.
You've tried to write some very imperative-looking code, and frankly, it's a bit of a mess. If you try to write your SML code as if it was Java, well, that's gonna hurt.
Instead of trying to fix your original code, let's redo it in a more functional style. First of all, pattern matching. In your code, you use an if-then-else
expression to check if your list is empty. Instead, we'll use pattern matching:
fun horner ([] , x) = 0.0
| horner (n::ns, x) = ...
This has two benefits. First, it splits the list up for us - we can now use n
to refer to the first item in the list, and ns
to refer to the rest. Second, it's way more readable.
Now we need the actual math. Now, horner's method uses a variable, which you've called result
in your code, to accumulate the answer. However, we're coding in a mostly functional language, and avoiding ref
s would be nice. Instead, we'll add an extra parameter to the function.
fun horner ([] , x, acc) = acc
| horner (n::ns, x, acc) = ...
Of course, we want the function to be usable with only two parameters, so we put the math in a helper function, and make the real function call the helper function:
fun horner' ([] , x, acc) = acc
| horner' (n::ns, x, acc) = ...
fun horner (xs, x) = horner' (xs, x, 0.0)
This is a fairly common pattern to see in functional programming, and SML has tools to hide the helper function so we don't clutter up the global namespace. For example, we could put the helper function inside a let
-expression:
fun horner (xs, x) = let
fun horner' ([] , x, acc) = acc
| horner' (n::ns, x, acc) = ...
in
horner' (xs, x, 0.0)
end
Finally, we add the recursive call of 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
And here's an of what happens when we call the horner
function:
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
来源:https://stackoverflow.com/questions/25099601/horners-algorithm-in-sml