SML, Using foldr to define min of a list - sml

I need to find the minimum value of a list using foldr.
Here’s the code I wrote:
fun minlist nil = nil
| minlist (x::xs) = List.foldr (fn (y,z) => if y < z then y else z) x xs;
However I’m getting an error: “Overloaded > cannot be applied to argument(s) of type ‘a list”
I’ve been stuck for a while. Any help is appreciated

Your first clause says that the minimum value of the empty list is a list.
Thus, (fn (y,z) => if y < z then y else z) produces a list, and y and z must also be lists.
There is no sensible value you can produce for an empty list, so you should either remove that case and live with the compilation warning, or raise an exception.

Finding the minimum of two values
Your expression if y < z then y else z has a built-in name Int.min (y, z).
Dealing with empty lists
You handle the empty list as minlist nil = nil, which means that "the smallest int of an empty int list is the empty list". But the empty list is not an int and so cannot be an element in an int list, or the return value for a function that otherwise returns smallest ints.
As molbdnilo also says, you could either live with a compilation warning (and risk having a Match exception raised at runtime if you ever feed the function an empty list), or raise a specific exception such as Empty when given the empty list. Neither are good, but the latter at least makes the problem clear.
Writing this without foldr it might look like:
fun minimum [] = raise Empty
| minimum [x] = x
| minimum (x::xs) = Int.min (x, minimum xs)
Converting a recursive function to a fold
Given some recursive function foo that depends on some function bar and some default value acc:
fun foo [] = acc
| foo (x::xs) = bar (x, foo xs)
you may notice the similarities between minimum and foo:
acc is x, some minimum value
bar is Int.min.
This is an attempt to generalise the recursion scheme of minimum.
Given the function foldr:
fun foldr f e [] = e
| foldr f e (x::xs) = f (x, foldr f e xs);
you may notice the same similarities:
f is bar, but made into a parameter
e is acc, but made into a parameter
The only thing from minimum that does not fit this general recursion scheme is handling the empty list. So you still have to do that separate from foldr:
fun minimum [] = ...
| minimum (x::xs) = foldr ...
But the rest is similar.
Error-aware return types
A third option would be to change the type signature of the function into
val minimum : int list -> int option
which your current exercise perhaps disallows.
Writing this without foldr it might look like:
fun minimum [] = NONE
| minimum [x] = SOME x
| minimum (x::xs) =
case minimum xs of
NONE => SOME x
| SOME y => SOME (Int.min (x, y))
or better yet:
fun minimum [] = NONE
| minimum [x] = SOME x
| minimum (x::xs) = Option.map (fn y => Int.min (x, y)) (minimum xs)
Converting this function to use foldr is the same process, but with a different f.
Tail recursion
The minimum function without folding (repeated from above):
fun minimum [] = raise Empty
| minimum [x] = x
| minimum (x::xs) = Int.min (x, minimum xs)
has a problem being that it mainly uses stack memory.
This can be illustated by evaluating the function by hand:
minimum [1,2,3,4,5]
~> Int.min (1, minimum [2,3,4,5])
~> Int.min (1, Int.min (2, minimum [3,4,5]))
~> Int.min (1, Int.min (2, Int.min (3, minimum [4,5])))
~> Int.min (1, Int.min (2, Int.min (3, Int.min (4, minimum [5]))))
~> Int.min (1, Int.min (2, Int.min (3, Int.min (4, 5))))
~> Int.min (1, Int.min (2, Int.min (3, 4)))
~> Int.min (1, Int.min (2, 3))
~> Int.min (1, 2)
~> 1
Since the outer Int.min cannot be calculated before the recursive call has returned, the amount of stack memory used to compute the function grows proportional to the length of the list.
You can avoid this by using an accumulating argument:
fun minimum [] = raise Empty
| minimum (y::ys) =
let fun helper [] acc = acc
| helper (x::xs) acc = helper xs (Int.min (x, acc))
in helper ys y end
Evaluating this function by hand:
minimum [1,2,3,4,5]
~> helper [2,3,4,5] 1
~> helper [3,4,5] (Int.min (2, 1))
~> helper [3,4,5] 1
~> helper [4,5] (Int.min (3, 1))
~> helper [4,5] 1
~> helper [5] (Int.min (4, 1))
~> helper [5] 1
~> helper [] (Int.min (5, 1))
~> helper [] 1
~> 1
Since Int.min is commutative, you might as well solve this exercise with foldl instead of foldr in the exact same way as you would have above, and you'd have a tail-recursive variant that uses less stack space.

Related

Why is the variable "hd" unbound here?

let f x =
match x with
((2, 4)::xr) -> 42
| [(1, y); (_, 3); (_, 4)] -> 5
| [(x, _); (u, w)] -> u + x
| [(44, 11); (12, 3)] -> 42
| (x::xr) -> fst (hd xr)
I've tried running f[(2, 4)] for example.
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ
You haven't described the environment you're running in, so it's not really possible to say for sure. But hd is defined in the List module. Most likely you need to write List.hd instead of hd:
# hd;;
Error: Unbound value hd
# List.hd;;
- : 'a list -> 'a = <fun>
#
Jeffrey's answer seems likely. It's worth noting that you can accomplish this without ever calling List.hd by using pattern-matching to bind x to the first element of the head of the tail of the list. The head of the tail otherwise being "the second element in a list which has at least two elements."
let f x =
match x with
(2, 4)::xr -> 42
| [(1, y); (_, 3); (_, 4)] -> 5
| [(x, _); (u, w)] -> u + x
| [(44, 11); (12, 3)] -> 42
| _::(x, _)::_ -> x
Assuming hd was meant to be List.hd in your original code, you may have gotten an exception. Of your previous patterns, only (2, 4)::xr can match a list with one element, and only if that element is (2, 4).
As it is, the code I've shown now features non-exhaustive pattern-matching, and that could generate an exception.

What is the logic behind this function named "picks"?

picks :: [a] -> [(a, [a])]
picks [] = []
picks (x:xs) = (x,xs) : [(y,x:ys)| (y,ys) <- picks xs]
picks [1..4] = [(1,[2,3,4]),(2,[1,3,4]),(3,[1,2,4]),(4,[1,2,3])]
This Haskell function works like a charm, but why? The first two tuples in the list are obvious enough, but how is the rest build up, just cracks my brain.
What does picks do? It returns all possible ways to choose one element from the list, in the form of a tuple (choice, rest), where choice is the item you chose and rest is the elements you did not choose. Note that [choice] ++ rest always contains the same elements as the original list, though not necessarily in the same order.
So how does picks work? When the argument is empty, it's simple: there are no ways to choose one element, so we return the empty list.
picks [] = []
When the argument is not empty, we can do one of two things. Either x is the first element of the tuple, or it is part of the second element. The easy thing to do is pick the first element; we unpack the list with (x:xs) and produce (x, xs).
picks (x:xs) = (x, xs) : ?
The other thing we can do is not pick x, but instead pick an element from xs. How do choose an element from xs? We use picks! This time, picks returns a list of tuples of where x is neither the first element nor a member of the second element. We just combine (x, xs) with this list.
-- x != y, x `elem` ys == False
picks (x:xs) = (x, xs) : [ (y, ?) | (y, ys) <- picks xs]
But x does need to be an member of the second element, because it's not the first element. So we have to put it back. The easiest place to put it is at the beginning of ys in each case:
picks (x:xs) = (x, xs) : [ (y, x:ys) | (y, ys) <- picks xs]
In many cases it helps to expand an expression manually:
picks [1..4] = (1, [2..4]) : [(y, 1:ys) | (y, ys) <- picks [2..4]]
-- continuing with picks [2..4]
picks [2..4] = (2, [3..4]) : [(y, 2:ys) | (y, ys) <- picks [3..4]]
-- continuing with picks [3..4]
picks [3, 4] = (3, [4]) : [(y, 3:ys) | (y, ys) <- picks [4]]
-- continuing with picks [4]
picks [4] = (4, []) : [(y, 4:ys) | (y, ys) <- picks []]
= (4, []) : [(y, 4:ys) | (y, ys) <- []]
= (4, []) : []
= [(4, [])]
picks [3, 4] = (3, [4]) : [(y, 3:ys) | (y, ys) <- [(4, [])]]
= (3, [4]) : [(4, 3:[])]
= (3, [4]) : [(4, [3])]
= [(3, [4]), (4, [3])]
-- and so one
The recursive case will return a list where the first item (x, xs) return a 2-tuple with as first item (the item we have picked) x, and with as remaining items the picks we make on the tail of the list and prepend all these items with x.
If we run this on a singleton list, for example [1], we thus get as options:
picks [1] = (1, []) : [(y, 1: ys) | (y,ys) <- picks []]
since picks [] is equivalent to [], this thus means that we retrieve:
picks [1] = (1, []) : [(y, 1: ys) | (y,ys) <- []]
hence the list comprehension will generate an empty list, and thus the result of picks [1] is:
picks [1] = [(1, [])]
If we now work with lists with two elements, the recursive call will return a list with one element: the only element of the tail and an empty list.
This thus means that if we run picks on picks [1,2], we thus get:
picks [1, 2] = (1, [2]) : [(y, 1:ys) | (y,ys) <- picks [2]]
and since picks [2] returns [(2, [])], we thus will prepend the empty list in the (2, []) tuple with one, and we thus obtain:
picks [1, 2] = (1, [2]) : [(y, 1:ys) | (y,ys) <- [(2, [])]]
= (1, [2]) : [(2, [1])]
= [(1, [2]), (2, [1])]
The x:ys part in the list comprehension will prepend the head of the list, so 1 to the lists returned by picks [2]. Since is not picked by the recursive call (we call picks recursively on the tail of the item), we thus need to insert it somewhere in the list, and the most easiest way is to prepend it.
If we thus work with three items, we will retrieve the data as:
picks [1, 2, 3] = (1, [2, 3]) : [(y, 1:ys) | (y,ys) <- picks [2, 3]]
= (1, [2]) : [(y, 1:ys) | (y,ys) <- [(2, [3]), (3, [2])]]
= (1, [2]) : [(2, [1, 3]), (3, [1, 2])]
= [(1, [2]), (2, [1, 3]), (3, [1, 2])]
and so for lists with more than three items, the recursion each time will prepend the item that is definitely not picked by the recursive tail of picks xs, and prepend the lists of non-picked items with x.
This is a case where the formulation of the algorithm using higher order functions actually looks clearer than with a list comprehensions--based one:
picks [] = []
picks (x:xs) = -- (x,xs) : [(y, x:ys) | (y,ys) <- picks xs]
(x,xs) : map (second (x:)) (picks xs)
In case you don't understand what second (x:) is, you can read it as a pseudocode: it applies (x:) to the second part of a pair, so that second (x:) (a,b) = (a, x:b). And map does so for every element in its argument list (the map's second argument).
Thus we have, building our understanding from the ground up, stating with one-element lists, then two elements, three, and so on, to see the pattern:
picks ([1]) = picks (1:[]) =
-- picks (x:xs) --
= (x,xs) : map (second (x:)) (picks xs)
= (1,[]) : map (second (1:)) (picks [])
= (1,[]) : map (second (1:)) []
= (1,[]) : []
= [(1,[])]
picks [2,1] = picks (2:[1]) =
= (2,[1]) : map (second (2:)) (picks [1])
= (2,[1]) : map (second (2:)) [(1, [])]
= (2,[1]) : [(1,[2])]
= [(2,[1]) , (1,[2])]
picks [3,2,1] =
= (3,[2,1]) : map (second (3:)) (picks [2,1])
= (3,[2,1]) : map (second (3:)) [(2, [1]) , (1, [2])]
= [(3,[2,1]) , (2,[3,1]) , (1,[3,2])]
picks [4,3,2,1] =
= (4,[3,2,1]) : map (second (4:)) [(3,[2,1]) , (2,[3,1]) , (1,[3,2])]
= [(4,[3,2,1]) , (3,[4,2,1]) , (2,[4,3,1]) , (1,[4,3,2])]
picks [5,4,3,2,1] =
= [([5,[4,3,2,1]), (4,[5,3,2,1]), (3,[5,4,2,1]), (2,[5,4,3,1]), (1,[5,4,3,2])]
....
Putting them together to better see the pattern, the results are:
picks [ ] = [ ]
picks [ 1] = [ (1,[ ])]
picks [ 2,1] = [ (2,[ 1]) , (1,[ 2])]
picks [ 3,2,1] = [ (3,[ 2,1]) , (2,[ 3,1]) , (1,[ 3,2])]
picks [ 4,3,2,1] = [ (4,[ 3,2,1]) , (3,[ 4,2,1]) , (2,[ 4,3,1]) , (1,[ 4,3,2])]
picks [5,4,3,2,1] =
= [([5,[4,3,2,1]) , (4,[5,3,2,1]) , (3,[5,4,2,1]) , (2,[5,4,3,1]) , (1,[5,4,3,2])]
....
And so picks produces all the ways to pick an element, pairing it up with the remaining elements in the list after the element is removed from it.
It evidently does so for the length 0 (empty) list case, [], and the length 1 (singleton) case [] and the length 2 case [2,1] as seen above; and if it does so for a list of length n, then for the n+1 we know that it's right as well since it starts with the first pick, and then the map adds the first element into each of the remainders in the result produced for the n case. Which is correct.
Yes, you can read this as both "the n case is correct" and "hence, n+1 is correct". Thus (and given the correctness of the 0 case) by the induction principle the results are correct for any n. That is to say, for all of them. Yes there are infinitely many of them but each n in itself is finite.
If the starting point is right, and each step is right, then the whole journey must be right as well. We don't need to understand how exactly it does what it does for an n case, unrolling all the layers of recursion. That's hard. Instead, we prove the inductive step is right, the base case is right, and that's that.
Recursion is a leap of faith.
The three most important rules in trying to understand how does a recursive function exactly do what it does, are:
The first rule is, we do not talk about how does a recursive function exactly do what it does.
The second rule is, we do not talk about how does a recursive function exactly do what it does.
The third rule is, we do not talk about how does a recursive function exactly do what it does.
Of course this version of picks is not too good. It is quadratic, and it destroys information.
We can address both flaws at once with
-- unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
picks3 :: [a] -> [([a], a, [a])]
picks3 xs = unfoldr (\case { (_,[]) -> Nothing ;
(a,x:xs) -> Just ((a,x,xs), (x:a,xs)) })
([],xs)
So that
> picks3 [1..4]
[([],1,[2,3,4]),([1],2,[3,4]),([2,1],3,[4]),([3,2,1],4,[])]
Now this is linear, and it is easy to produce the output of picks from it, if we so choose and are willing to pay the price.
Without brain - cracking, simple to explain (but Eq a =>), has approximately 1.7 slower execution time trade off
mypicks :: Eq a => [a] -> [(a,[a])]
mypicks [] = []
mypicks lst = [ zsplit x lst | x <- lst]
zsplit :: Eq a => a -> [a] -> (a,[a])
zsplit z lst = esplit z lst []
where
esplit :: Eq a => a -> [a] -> [a] -> (a, [a])
esplit e [] lr = (e, lr)
esplit e (x:xs) lr
| e == x = (e, reverse lr ++ xs)
| otherwise = esplit e xs (x:lr)
--- using
perms2 [] = [[]]
perms2 xs = [x:zs | (x,ys) <- picks xs, zs <- perms2 ys]
perms2' [] = [[]]
perms2' xs = [x:zs | (x,ys) <- mypicks xs, zs <- perms2' ys]
--- and
T.measureTime $ length $ perms2 [1..9]
T.measureTime $ length $ perms2' [1..9]
--- delivers:
e: 362880
Computation time: 0.075562000 sec.
e: 362880
Computation time: 0.125598000 sec.

SML - Find occurences in lists to form ordered pairs

I'm trying to write a function in SML that takes in a list of ints and will output a list of ordered pairs of ints. The ordered pairs first int is the int that occurred in the input list and the second int in the ordered pair is the number of times it occurred in the input list. Also the list returned should be in ascending order according to the first int in the ordered pairs.
For example input list [1, 1, 1, 2, 3, 3, 5] would output as [(1,3), (2, 1), (3, 2), (5, 1)].
So far I have a function that uses foldl
UPDATED the code since original post.
fun turnIntoPairs l = foldl (fn (e, a) => if List.exists (fn (x, _) => x = e) a then x + 1 else a # [(e, 1)]) [] l;
I'm having trouble updating the list where I find the ordered pair that is already in the list - I want to add one to the second int in the ordered pair that was found while it's still in the list.
Any help would be greatly appreciated!
C:\Program Files (x86)\SMLNJ\\bin\.run\run.x86-win32.exe: Fatal error -- Uncaught exception Error with 0
raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
[autoloading done]
C:\Users\Localadmin\Desktop\CS 671\Program 3\commonFactors.sml:1.87 Error: unbound variable or constructor: x
C:\Users\Localadmin\Desktop\CS 671\Program 3\commonFactors.sml:1.44-1.110 Error: types of if branches do not agree [literal]
then branch: int
else branch: (''Z * int) list
in expression:
if (List.exists (fn <pat> => <exp>)) a
then <errorvar> + 1
else a # (e,1) :: nil
[Finished in 0.5s with exit code 1]
Not really sure how to fix your current program, but you can solve this problem by splitting it in two: grouping equal elements and then ordering the list.
(* Groups successive equal elements into a tuples (value, count) *)
fun group (l as (x :: _)) =
let val (firstGroup, rest) = List.partition (fn y => x = y) l
in
(x, List.length firstGroup) :: (group rest)
end
| group [] = []
(* Now that we have our elements grouped, what's left is to order
them as required. *)
fun turnIntoPairs xs =
ListMergeSort.sort (fn ((x, _), (y, _)) => x >= y) (group xs)
Let's just look at the function you're passing to foldl:
(fn (e, a) => if List.exists (fn (x, _) => x = e) a then x + 1 else a # [(e, 1)])
The first problem (which the type-checker is complaining about) is that your if expression returns either x + 1, or a # [(e, 1)], which seems problematic on account of the former being a value of type int and the latter being of type (int * int) list.
Let's rewrite your code using some helper functions that I won't define and see if it gets clearer:
(fn (e, a) => if List.exists (fn (x, _) => x = e) a then increment a e else a # [(e, 1)])
Where increment has the type (int * int) list -> int -> (int * int) list.
Can you implement increment?
Like Gian, I would prefer to divide this into two functions: One that folds and one helper function that inserts. Incidentally, the insert function would take an element and an existing (int * int) list just as the accumulator function that fold accepts these two arguments.
Normally I would write an insert function curried (i.e. insert x xs) but if I write it uncurried (i.e. insert (x, xs)), I can pass it directly to foldl:
fun insert (x, []) = [(x,1)]
| insert (x, ((y,c)::xs)) =
if x = y then (y,c+1)::xs else (y,c)::insert (x, xs)
fun turnIntoPairs xs = foldl insert [] xs

How do I find largest number in List in SML

We want to find the largest value in a given nonempty list of
integers. Then we have to compare elements in the list. Since data
values are given as a sequence, we can do comparisons from the
beginning or from the end of the list. Define in both ways. a)
comparison from the beginning b) comparison from the end (How can
we do this when data values are in a list?)
What I have done is find the largest number by comparison from the beginning.
How can I do it from the end? What logic should I apply?
Here is my code for comparing from the beginning.
- fun largest[x] = x
= | largest(x::y::xs) =
= if x>y then largest(x::xs) else largest(y::xs)
= | largest[] = 0;
val largest = fn : int list -> int
output
- largest [1,4,2,3,6,5,4,6,7];
val it = 7 : int
In your function, first two elements of the list are compared and the bigger value is compared to the remaining elements. I think comparison from the end means that you try to find the largest number of the tail of the list first and compare it with the head element later.
fun largest [] = raise Empty
| largest [x] = x
| largest (x::xs) =
let
val y = largest xs
in
if x > y then x else y
end
Although it is not required, you should handle the case of empty list for completeness. And you can shorten the function if using max function.
fun largest [] = raise Empty
| largest [x] = x
| largest (x::xs) = max(x, largest xs)
To be honest, I would prefer your version which is tail-recursive (it doesn't blow the stack on big lists). My function could be rewritten to be tail-recursive as other answers demonstrated, but certainly it is more sophisticated than your function.
As #pad demonstrates with his code, the logic that should be applied is making a recursive call that solves the sub-problem recursively before solving the problem of the current scope of the function.
In the case of largest, there is not really any point in solving it backwards, since it simply uses more stack space, which becomes apparent when executing the code "by hand". The design pattern is however useful in other situations. Imagine a function called zip:
(* zip ([1,2,3,4], [a,b,c]) = [(1,a),(2,b),(3,c)] *)
fun zip (x::xs, y::ys) = (x,y) :: zip (xs, ys)
| zip _ = []
This function turns a tuple of two lists into a list of many tuples, discarding left-over values. It may be useful in circumstances, and defining it is not that bad either. Making its counterpart, unzip, is however slightly trickier:
(* unzip ([(1,a),(2,b),(3,c)] = ([1,2,3],[a,b,c]) *)
fun unzip [] = ([], [])
| unzip ((x,y)::xys) =
let
val (xs, ys) = unzip xys
in
(x::xs, y::ys)
end
Running the regular "from the beginning"-largest by hand might look like this:
largest [1,4,2,3,6,5,4,6,7]
~> largest [4,2,3,6,5,4,6,7]
~> largest [4,3,6,5,4,6,7]
~> largest [4,6,5,4,6,7]
~> largest [6,5,4,6,7]
~> largest [6,4,6,7]
~> largest [6,6,7]
~> largest [6,7]
~> largest [7]
~> 7
Running the "from the end"-largest by hand, imagining that every indentation level requires saving the current context of a function call in stack memory, calling a new function and returning the result after the ~> arrow, might look like this:
largest [1,4,2,3,6,5,4,6,7] ~> 7
\_
largest [4,2,3,6,5,4,6,7] ~> 7
\_
largest [2,3,6,5,4,6,7] ~> 7
\_
largest [3,6,5,4,6,7] ~> 7
\_
largest [6,5,4,6,7] ~> 7
\_
largest [5,4,6,7] ~> 7
\_
largest [4,6,7] ~> 7
\_
largest [6,7] ~> 7
\_
largest [7] ~> 7
So why are these non-tail-recursive functions that make early recursive calls useful if they simply use more memory? Well, if we go back to unzip and we want to solve it without this annoying "thinking in reverse", we have a problem constructing the new result, which is a tuple, because we don't have anywhere to put the x and y:
(* Attempt 1 to solve unzip without abusing the call stack *)
fun unzip [] = ([], [])
| unzip ((x,y)::xys) = ...something with x, y and unzip xys...
One idea for making such a place would to create an auxiliary function (helper function) that has a few extra function parameters for building xs and ys. When the end of the xys list is reached, those values are returned:
(* Attempt 2 to solve unzip without abusing the call stack *)
local
fun unzipAux ([], xs, ys) = (xs, ys)
| unzipAux ((x,y)::xys, xs, ys) = unzipAux (xys, x::xs, y::ys)
in
fun unzip xys = unzipAux (xys, [], [])
end
But you might have realized that those (xs, ys) end up reversed in the result. A quick way to fix this is by using rev on them, once only, which is best achieved at the base case:
(* Attempt 3 to solve unzip without abusing the call stack *)
local
fun unzipAux ([], xs, ys) = (rev xs, rev ys)
| unzipAux ((x,y)::xys, xs, ys) = unzipAux (xys, x::xs, y::ys)
in
fun unzip xys = unzipAux (xys, [], [])
end
Which brings forth an interesting question: How is rev implemented?
I suggest using a tail recursive helper, which passes the current maximum as an accumulator.
local
fun helper max [] = max
| helper max (n::ns) = helper (if n > max then n else max) ns
in
fun largest ns = helper 0 ns
end;
(*Find the max between two comparable items*)
fun max(a,b) = if a>b then a else b;
(*Find the max item in list which calls the maxL function recursively*)
fun maxL(L) = if L=[] then 0 else max(hd(L), maxL(tl(L)));
I know it is too late to answer your question, but hopefully this will help:
fun insert (x, []) = [x]
| insert (x, y::ys) = if x<=y then x::y::ys else y::insert(x,ys);
fun insertion_sort [] = []
| insertion_sort (x::xs) = insert(x, insertion_sort xs);
fun get_last_element [] = 0
| get_last_element [x] = x
| get_last_element (x::xs) = if(xs=nil)
then x
else
get_last_element(xs);
fun get_min L = if(insertion_sort(L)=[])
then 0
else
hd(insertion_sort(L));
fun get_max L = get_last_element(insertion_sort(L));
You also can tweak the code e.g. passing anonymous function in insert function ...

SML: subtract one list from another list

What is the easiest way to subtract one list from another? Do I need to use ListPair to solve this task? Notic that I need to compare ROWS, not single elements. For instance, there are two lists "L1" and "L2":
L1 =
[(1, 2, 3),
(4, 5, 6)]
L2 =
[(1, 2, 3),
(4, 5, 6),
(3, 2, 3]
I need to get "L3" by applying L3 = L2-L1:
L3 =
[(3, 2, 3)]
Thanks.
As I understand the question, you want to remove the elements in L2 which are also in L1, but only once per occurrence.
A simple solution might involve a helper function to tell you if an element was found in L1, along with the rest of L1 with this element removed.
fun remFirst _ [] rest = (false, rev rest)
| remFirst x (y::ys) rest =
if x = y then
(true, rev rest # ys)
else
remFirst x ys (y :: rest)
Now you can iterate through L2, discarding elements each time remFirst returns true, and then proceeding with the rest of the list.
If instead you want to remove the prefix which L2 has in common with L1, things get a bit simpler.
fun remPref [] _ = []
| remPref xs [] = xs
| remPref (x::xs) (y::ys) = if x = y then remPref xs ys else (x::xs)
UPDATE: The question has now been altered.
If the requirement is now to remove elements from L2 that are in L1, filter is useful.
List.filter (fn x => List.all (fn y => x <> y) L1) L2