SML Sum of List using option and Pattern matching - functional-programming

I'm creating sum of list and using option in it. When I pass an empty list, I should get NONE or else SOME value.
I'm able to do that in the following way:
fun sum_list xs =
case xs of
[] => NONE
| x =>
let
fun slist x =
case x of
[] => 0
| x::xs' => x + slist xs'
in
SOME (slist x)
end
But I want to do it in the other way round using pattern matching, in which I want to eval the result of sum_list to see whether it is NONE or contains some other value.
I have tried in various ways but I cannot get a hang of how to do in that way.

I think what you currently have is very clear and easy to understand.
If you want to avoid using slist, you have to call sum_list recursively on the tail of the list, pattern-match on that option value and return appropriate results:
fun sum_list xs =
case xs of
[] => NONE
| x::xs' => (case (sum_list xs') of
NONE => SOME x
| SOME y => SOME (x+y))

Related

Issue in sorting SML list

I am new to SML.I got this sorting algo to implement where in each iteration,I have to pick minimum element from the list, remove it and create sorted list.
I did below coding to solve the problem.
I wrote 2 helper functions to pickup minimum element from the list and remove one element from the list.
fun minList(x::xs) =List.foldl (fn (x,y)=> if x<y then x else y) x (x::xs);
fun remElem(x, l) =
case l of
[] => []
| (x1::x2::xs) => if x1=x then (x2::xs) else (x1::xs)
;
Above two programs ran successfully.
Below is my sorting code.
fun simpSort(xs)=
let fun aux(xs,acc)=
case xs of
[] =>acc
| [x] => [x]
| (x::xs) => let val m = minList(xs)
in
aux(remElem(m,xs),acc#[m])
end
in aux(xs,[])
end;
This sorting program is giving error.
simpSort([3,1]);
uncaught exception Match [nonexhaustive match failure]
raised at: stdIn:433.59
Please advise.
Since you've solved your problem, here are some hints for improving a working version of your code:
Find the minimum of a list in a way that supports empty lists:
fun minimum [] = NONE
| minimum (x::xs) = SOME (foldl Int.min x xs)
Simplify pattern matching in the function that removes the first occurrence of an element from a list:
fun remove (_, []) = []
| remove (y, x::xs) =
if x = y
then xs
else x :: remove (y, xs)
Use those in combination to write simpSort:
fun simpSort xs =
case minimum xs of
NONE => []
| SOME x => x :: simpSort (remove (x, xs))
I shouldn't have to say that this sorting algorithm is terribly inefficient. :-P

Filtering elements of one list by looking at boolean values from the second list

I have two lists of equal length. I want to filter the elements of the first list by looking, if the element, with the same index in the second list, has a true boolean value.
Example:
[1,2,3,4,5]:int list
[true,false,false,true,false]:bool list
Expected result: [1,4]
I know two ways I could achieve this:
1) Write a function that takes two lists. For every element in the first list, that I want to append, check if the current(head) element of the second list is true.
2) Zip the two lists and filter it according to the boolean value.
There should be an easier to go about this, right?
Not really. The cleanest way to do this is probably
List.map (fn (x,y) => x) (List.filter (fn (x,y) => y) (ListPair.zip (L1,L2)))
or
List.map Option.valOf (List.filter Option.isSome (ListPair.map(fn (x,y) => if y then SOME x else NONE) (L1,L2)))
The recursive function isn't too bad, either:
fun foo ([],[]) = []
| foo ([],L) = raise Fail "Different lengths"
| foo (L,[]) = raise Fail "Different lengths"
| foo (x::xs, b::bs) = if b then x::foo(xs,bs) else foo(xs,bs)
Those are pretty much the two options you have; either recurse two lists at once, or combine them into one list of tuples and recurse that. There are several combinators you could use to achieve the latter.
val foo = [1,2,3,4,5];
val bar = [true,false,true,true,false];
val pairs = ListPair.zip (foo, bar)
Once zipped, here are two other ways you can do it:
val result = List.foldr (fn ((n,b), res) => if b then n::res else res) [] pairs
val result = List.mapPartial (fn (n,b) => if b then SOME n else NONE) pairs
The simplest is probably
ListPair.foldr (fn (x,y,z) => if y then x :: z else z) [] (L1, L2)
Don't know if ML has list comprehension, but if your language has it:
[ x | (x, True) <- zip xs ys ]

Changing to Tail Recursive SML

Ok, so I'm trying to change this function into Tail Recursive. The Definition I have of Tail Recursive is to use a "Local Helper Function" to accumulate my answer and return it without calling the primary function recursively.
these functions work properly.
fun same_string(s1 : string, s2 : string) =
s1 = s2
fun all_except_option (name, []) = NONE
| all_except_option (name, x::xs)=
case same_string (x , name) of
true => SOME xs
| false => case all_except_option(name,xs) of
NONE => NONE
| SOME z => SOME(x::z)
fun get_substitutions1 ([],name2) = [] (*get_substitutions2 is same but tail recursive *)
| get_substitutions1 (x::xs,name2) =
case all_except_option (name2,x) of
NONE => get_substitutions1 (xs,name2)
| SOME z => z # get_substitutions1(xs,name2)
So here are my attempts at tail recursion which do not work and I think I am missing something fairly basic that I am overlooking due to my lack of experience in SML.
fun get_substitutions2 (lst,name3) =
let fun aux (xs,acc) =
case all_except_option(name3,x::xs) of
NONE => aux(xs, acc)
| SOME z => aux(xs, z::acc)
in
aux(lst,[])
end
and
fun get_substitutions2 (lst,name3) =
let fun aux (xs,acc) =
case all_except_option(name3,x::xs) of
NONE => aux(xs, acc)
| SOME z => aux(xs, z#acc)
in
aux(lst,[""])
end
Both "get_substitutions" functions are supposed to do the same thing.
compare String1 to string list list, return single list made up of all lists containing String1 minus String1.
My attempts at using Tail Recursion have resulted in the following error.
Error: unbound variable or constructor: x
uncaught exception Error
raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
../compiler/TopLevel/interact/evalloop.sml:44.55
../compiler/TopLevel/interact/evalloop.sml:296.17-
Here are a few examples of calling get_substitutions2:
get_substitutions2 ([["foo"],["there"]], "foo"); (* = [] *)
get_substitutions2 ([["fred","fredrick","freddie","F","freddy"],["Will","William","Willy","Bill"]],"Bill"); (* = ["Will","William","Willy"] *)
get_substitutions2 ([["a","b"],["a","c"],["x","y"]], "a"); (* = ["c","b"] *)
You need to use the same patterns you had for get_substitutions1 in your aux function definition:
fun get_substitutions2 (lst,name3) =
let fun aux ([],acc) = acc (* BASE CASE *)
| aux (x::xs,acc) = (* BINDING x IN PATTERN *)
case all_except_option(name3,x) of
NONE => aux(xs, acc)
| SOME z => aux(xs, z#acc)
in
aux(lst,[])
end

Standard ML - Return the index of the occurrences of a given value in a list

I'm trying to figure out how to return a list of the indexes of occurrences of a specific value in another list.
i.e.
indexes(1, [1,2,1,1,2,2,1]);
val it = [1,3,4,7] int list
I'm trying to figure out how lists work and trying to get better at recursion so I don't want to use List.nth (or any library functions) and I don't want to move into pattern matching quiet yet.
This is what I have so far
fun index(x, L) =
if null L then 0
else if x=hd(L) then
1
else
1 + index(x,tl L);
fun inde(x, L) =
if null L then []
else if x=hd(L) then
index(x, tl L) :: inde(x, tl L)
else
inde(x, tl L);
index(4, [4,2,1,3,1,1]);
inde(1,[1,2,1,1,2,2,1]);
This gives me something like [2, 1, 3, 0]. I guess I'm just having a hard time incrementing things properly to get the index. The index function itself works correctly though.
Instead you could also make two passes over the list: first add an index to each element in the list, and second grap the index of the right elements:
fun addIndex (xs, i) =
if null xs then []
else (hd xs, i) :: addIndex(tl xs, i+1)
fun fst (x,y) = x
fun snd (x,y) = y
fun indexi(n, xs) =
if fst(hd xs) = n then ... :: indexi(n, tl xs)
else indexi(n, tl xs)
(I left out part of indexi for the exercise.)
Where addIndex([10,20,30],0) gives you [(10,0),(20,1),(30,2)]. Now you can use addIndex and indexi to implement your original index function:
fun index(n, xs) = indexi(n, addIndex(xs, 0))
When you get that to work, you can try to merge addIndex and indexi into one function that does both.
However, you really want to write this with pattern matching, see for instance addIndex written using patterns:
fun addIndex ([], _) = []
| addIndex (x::xs, i) = (x,i) :: addIndex(xs, i+1)
If you do index(1,[2]), it gives 1, which is not correct. When the list is empty, it gives you zero. In a function like this, you'd probably want to use SOME/NONE feature.

New to SML / NJ. Adding numbers from a list of lists

Define a function which computes the sum of all the integers in a
given list of lists of integers. No 'if-then-else' or any auxiliary
function.
I'm new to to functional programming and am having trouble with the correct syntax with SML. To begin the problem I tried to create a function using pattern matching that just adds the first two elements of the list. After I got this working, I was going to use recursion to add the rest of the elements. Though, I can't even seem to get this simple function to compile.
fun listAdd [_,[]] = 0
| listAnd [[],_] = 0
| listAnd [[x::xs],[y::ys]] = x + y;
fun listAdd [] = 0
| listAdd ([]::L) = listAdd L
| listAdd ((x::xs)::L) = x + listAdd (xs::L)
should do what it looks like you want.
Also, it looks like part of the problem with your function is that you give the function different names (listAdd and listAnd) in different clauses.
For the sake of simplicity, I'd say you probably want this :
fun listAdd : (int * int) list -> int list
Now, I would simply define this as an abstraction of the unzip function :
fun listAdd ls :
case ls of
[] => 0
| (x,y) :: ls' => (x + y) + (listAdd ls')
I think there is no point in taking two separate lists. Simply take a list that has a product of ints. If you have to build this, you can call the zip function :
fun zip xs ys :
case xs, ys of
[], [] => []
| xs, _ => []
| _, ys => []
| x::xs', y::ys' => (x,y) :: (zip xs' ys')
In general, if you really wanted, you can write a far more abstract function that is of the general type :
fun absProdList : ((`a * `b) -> `c) -> (`a * `b) list -> `c list
This function is simply :
fun absProdList f ls =
case l of
[] => []
| (x,y) :: ls' => (f (x,y)) :: (absProdList f ls')
This function is a supertype of the addList function you mentioned. Simply define an anonymous function to recreate your addList as :
fun addList' ls =
absProdList (fn (x,y) => x + y) ls
As you can see, defining the generic type-functions makes specific calls to functions that are type-substitutions to the general one far easier and much more elegant with the appropriate combination of : Currying, Higher-Order Functions and Anonymous Functions.
You probably don't want an int list list as input, but simply an int list * int list (pair of int lists). Besides this, your function seems to returns numbers rather than a list of numbers. For this you would use recursion.
fun listAdd (x::xs, y::ys) = (x + y) :: listAdd (xs, ys)
| listAdd ([], _) = []
| listAdd (_, []) = [] (* The last two cases can be merged *)
You probably want to read a book on functional programming fron the first page and on. Pick for example Notes on Programming in SML/NJ by Riccardo Pucella if you want a free one.

Resources