问题
I'm working on a program that appends either a '+' or '-' to an element of a list, depending on whether the index of that element is odd or even (i.e an alternating sums list).
However, I'm having trouble identifying what the index of each element is. I have code that I believe should append the correct symbol, using if statements and mod
fun alternating([]) = 0
| alternating(l) =
if List.nth(l,hd(l)) mod 2 == 0 then '+'@hd(l)@alternating(tl(l))
else '-'@hd(l)@alternating(tl(l))
However, List.nth(l,hd(l)) always returns the element at the second index, not the first.
回答1:
On the off chance that you really just want to negate integers them so you can pass them into some kind of summation, I would just negate the argument if it's odd. Using mutual recursion one can do it without any explicit index bookkeeping:
fun alternate l =
let
fun alternate1 [] = []
| alternate1 (x::xs) = (~x) :: alternate2 xs
and alternate2 [] = []
| alternate2 (x::xs) = x :: alternate1 xs
in
alternate1 l
end
It works like so:
- alternate [1,2,3,4];
val it = [~1,2,~3,4] : int list
I would strongly encourage you to use pattern matching instead of hd.
Edit discussing hd
As a rule of thumb, if you need hd you probably need tl as well. hd is a partial function--it's going to throw Empty if your list is empty. If you pattern match, you conveniently get variables for the head and tail of the list right there, and you get a visual reminder that you need to handle the empty list. It's more aesthetically pleasing, IMO, to see:
fun foo [] = ...
| foo (x::xs) = ...
than the equivalent
fun foo l =
if null l
then ...
else (hd l) ... (tl l)
In other words, you get shorter, cleaner code with an automatic reminder to make it correct. Win/win. To my knowledge there's no significant advantage to doing it the other way. Of course, you may find yourself in a situation where you know the list will have at least one element and you don't need to do anything else. You still have to consider the cases you're given, but it's a good rule of thumb.
回答2:
If you want to decorate your list with an index you could try something like the following
fun add_index l =
let
fun add_index_helper (nil, _) = nil
| add_index_helper (h::tl,i) = (h,i) :: add_index_helper (tl,1+i)
in
add_index_helper (l,0)
end
val x = add_index [0,1,4,9,16,25]
but you can also just directly compute parity with the same method
fun add_sign l =
let
fun add_sign_helper (nil, _) = nil
| add_sign_helper (h::tl,i) = (h,i) :: add_sign_helper (tl,1-i)
in
add_sign_helper (l,0)
end
val y = add_sign [0,1,4,9,16,25]
then you can map the parity to a string
fun sign_to_char (x,0) = (x,"+")
| sign_to_char (x,_) = (x,"-")
val z = List.map sign_to_char y
or you can just add the sign directly
fun add_char l =
let
fun add_char_helper (nil, _) = nil
| add_char_helper (h::tl,0) = (h,"+") :: add_char_helper (tl,1)
| add_char_helper (h::tl,_) = (h,"-") :: add_char_helper (tl,0)
in
add_char_helper (l,0)
end
val zz = add_char [0,1,4,9,16,25]
Alternatively if you had a string list and you wanted to add chars you could try something like this
fun signs L =
let
datatype parity = even | odd
fun signs_helper ( nil ,_) = nil
| signs_helper (x::xs,even) = ("+" ^ x) :: signs_helper(xs,odd)
| signs_helper (x::xs,odd) = ("-" ^ x) :: signs_helper(xs,even)
in
signs_helper (L,even)
end
val z = signs ["x","2y","3z","4"]
(* this gives you val z = ["+x","-2y","+3z","-4"] : string list *)
来源:https://stackoverflow.com/questions/26660505/sml-get-indices-of-list