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.
Related
I have a function that takes in a list and then puts elements into two different lists based on a condition. However, when I check the returned lists they are always empty. Why is this happening?
fun divide_list(l1: type list): (type list, type list) =
let
val count = ref 0
and list1 = nil
and list2 = nil
in
while !count <> 8 do (
if !count % 2 = 0 then
list1 # [List.nth(l1, !count)]
else
list2 # [List.nth(l1, !count)];
count := !count + 1
);
(list1, list2)
end
The output I get after running this is as follows:
val it = ([],[]) : type list * type list
You're not modifying the lists, you're creating new lists that are discarded. In order to achieve what you want, you'd need to also wrap the lists in references: and list1 = ref [] and list2 = ref []. Then, at each instance where you intend to modify them, you use := (as you have for modifying the count). Note that you'd rewrite the tuple you're returning to fetch the value held by each reference as well: (!list1, !list2).
As a sidenote, it is regrettable that Standard ML does not inform you of this. In OCaml, for example, the typing rule for sequencing expressions e ; e' ensures e evaluates to () : unit due to the way it's desugared (let () = e in e'). So, the OCaml analogue to your code wouldn't even typecheck.
I would dispense with the ref based solution entirely and do something using a fold, carrying the index:
fun divide xs =
let
fun choose (x, ((l, r), i)) =
(if i mod 2 = 0 then (x :: l, r) else (l, x :: r), i + 1)
val (l, r) =
#1 (List.foldl choose (([], []), 0) xs)
in
(List.rev l, List.rev r)
end
I build up the list partitions backwards and then reverse at the end to avoid quadratic blowup of appending to the end for every element. If you wish to have the length of 8 constraint, then you can combine the usage of the above function with List.take from the basis library.
#contificate has offered a good explanation.
If you're implementing a list partitioning function.
There's no reason not to factor out the function that will decide how to partition the list. This function only needs to take in a value and return a boolean value.
This is easily implemented in terms of a fold. There is no need, from what I can see, to keep track of the index.
fun partition f lst =
let
val (a, b) = List.foldl (fn (x, (a, b)) => if f x then (x::a, b) else (a, x::b)) ([], []) lst
in
(List.rev a, List.rev b)
end;
partition (fn x => x mod 2 = 0) [1, 2, 3, 4, 5];
Yields:
([2, 4], [1, 3, 5])
If you simply want to split based on index
If we're aiming to split a list into two lists based on the index:
[4, 7, 1, 9, 8]
Becomes:
([4, 1, 8], [7, 9])
That can be done entirely functionally as well with simple pattern matching and recursion.
let rec split lst (acc1, acc2) =
match lst with
| [] -> (acc1, acc2)
...
Here we're passing in the list to split, and an accumulator with the two lists. Obviously, if the list is empty, the result is just the accumulator. What if there's one element in the list?
let rec split lst (acc1, acc2) =
match lst with
| [] -> (acc1, acc2)
| [x] -> (x::acc1, acc2)
...
Well, that goes in the first list. What if there are more elements than one?
let rec split lst (acc1, acc2) =
match lst with
| [] -> (acc1, acc2)
| [x] -> (x::acc1, acc2)
| x::y::tail -> split tail (x::acc1, y::acc2)
Well, then we match the first two elements and the tail. We update the accumulator to place the first two elements in their respective lists, and call split again with the tail and that updated accumulator.
utop # split [4; 7; 1; 9; 8] ([], []);;
- : int list * int list = ([8; 1; 4], [9; 7])
Oops. They're backwards because of how we constructed the accumulators. We can use List.rev to fix this, but because we don't want to do it twice, when there's one element we'll call split on an empty list.
let rec split lst (acc1, acc2) =
match lst with
| [] -> (List.rev acc1, List.rev acc2)
| [x] -> split [] (x::acc1, acc2)
| x::y::tail -> split tail (x::acc1, y::acc2)
utop # split [4; 7; 1; 9; 8] ([], []);;
- : int list * int list = ([4; 1; 8], [7; 9])
And finally you can shadow split to remove the need to explicitly pass the tuple of empty lists.
let rec split lst (acc1, acc2) =
match lst with
| [] -> (List.rev acc1, List.rev acc2)
| [x] -> split [] (x::acc1, acc2)
| x::y::tail -> split tail (x::acc1, y::acc2)
let split lst = split lst ([], [])
My Problem is that I want to create a infinite list of all combinations of a given list. So for example:
infiniteListComb [1,2] = [[],[1],[2], [1,1],[1,2],[2,1],[2,2], [1,1,1], ...].
other example:
infiniteListComb [1,2,3] = [[], [1], [2], [3], [1,1], [1,2], [1,3], [2,1],[2,2],[2,3],[3,1],[3,2],[3,3],[1,1,1], ...].
Reminds me of power sets, but with lists with same elements in it.
What I tried:
I am new in Haskell. I tried the following:
infiniteListComb: [x] -> [[x]]
infiniteListComb [] = []
infiniteListComb [(x:xs), ys] = x : infiniteListComb [xs,ys]
But that did not work because it only sumed up my list again. Has anyone another idea?
Others already provided a few basic solutions. I'll add one exploiting the Omega monad.
The Omega monad automatically handles all the interleaving among infinitely many choices. That is, it makes it so that infiniteListComb "ab" does not return ["", "a", "aa", "aaa", ...] without ever using b. Roughly, each choice is scheduled in a fair way.
import Control.Applicative
import Control.Monad.Omega
infiniteListComb :: [a] -> [[a]]
infiniteListComb xs = runOmega go
where
go = -- a combination is
pure [] -- either empty
<|> -- or
(:) <$> -- a non empty list whose head is
each xs -- an element of xs
<*> -- and whose tail is
go -- a combination
Test:
> take 10 $ infiniteListComb [1,2]
[[],[1],[1,1],[2],[1,1,1],[2,1],[1,2],[2,1,1],[1,1,1,1],[2,2]]
The main downside of Omega is that we have no real control about the order in which we get the answers. We only know that all the possible combinations are there.
We iteratively add the input list xs to a list, starting with the empty list, to get the ever growing lists of repeated xs lists, and we put each such list of 0, 1, 2, ... xs lists through sequence, concatting the resulting lists:
infiniteListComb :: [a] -> [[a]]
infiniteListComb xs = sequence =<< iterate (xs :) []
-- = concatMap sequence (iterate (xs :) [])
e.g.
> take 4 (iterate ([1,2,3] :) [])
[[],[[1,2,3]],[[1,2,3],[1,2,3]],[[1,2,3],[1,2,3],[1,2,3]]]
> sequence [[1,2,3],[1,2,3]]
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]
> take 14 $ sequence =<< iterate ([1,2,3] :) []
[[],[1],[2],[3],[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3],[1,1,1]]
The essence of Monad is flatMap (splicing map).
sequence is the real magician here. It is equivalent to
sequence [xs, ys, ..., zs] =
[ [x,y,...,z] | x <- xs, y <- ys, ..., z <- zs ]
or in our case
sequence [xs, xs, ..., xs] =
[ [x,y,...,z] | x <- xs, y <- xs, ..., z <- xs ]
Coincidentally, sequence . replicate n is also known as replicateM n. But we spare the repeated counting from 0 to the growing n, growing them by 1 at a time instead.
We can inline and fuse together all the definitions used here, including
concat [a,b,c...] = a ++ concat [b,c...]
to arrive at a recursive solution.
Another approach, drawing on answer by chi,
combs xs = ys where
ys = [[]] ++ weave [ map (x:) ys | x <- xs ]
weave ((x:xs):r) = x : weave (r ++ [xs])
There are many ways to implement weave.
Since list Applicative/Monad works via a cartesian-product like system, there's a short solution with replicateM:
import Control.Monad
infiniteListComb :: [x] -> [[x]]
infiniteListComb l = [0..] >>= \n -> replicateM n l
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.
How I can iterate a list of elements four by four and then add these four card to a tuple?.
Basically this a function that receives the Suit that it was to be killed, the cards played by order and the player who has played first.
That game is played by pairs, so it returns a tuple with the cards won for the first couple and the cards won for the second couple.
winnedCards:: Suit-> [Card] -> Int -> ([Card],[Card])
winnedCards [] _ = ([],[])
winnedCards (Suit type) cardsPlayed positionFirstPlayPerson
| snd(xs) == 3 = (take 4 (cardsPlayed),[])
| snd(xs) == 1 = (take 4 (cardsPlayed),[])
| otherwise = ([],take 2 (cardsPlayed))
where xs = whoHasWon (take 4 (cardsPlayed)) (Suit type)
whoHasWon returns the position of the player who has won. I think I have to it recursevily because I have to iterate 4 by 4, and then add the result to the tuple after each iteration.
As Willem Van Onsem mentions in the comments, your function appears to do entirely too much work. If you're trying to split a list into groups of four-tuples, do that separately from the rest of the logic.
toFourTuple :: [a] -> [(a, a, a, a)]
toFourTuple [] = []
toFourTuple (a:b:c:d:rest) = (a, b, c, d) : toFourTuple rest
toFourTuple _ = error "list not divisible by four"
-- how should this be handled?
For the rest, it might be useful to know that the Monoid instance of Monoid a => (a, a) implements mappend as mappend (x, y) (x', y') = (x <> x', y <> y'), so if you generate a list of (leftside, rightside) sublists, you can mconcat them together.
xs = [ ([1] , [3])
, ([2, 4], [5])
, ([6] , [7, 9, 11, 13])
]
mconcat xs = ([1,2,4,6],[3,5,7,9,11,13])
Of course this works incrementally too.
-- |Separates [Int] into ([odds], [evens])
splitByMod2 :: [Int] -> ([Int], [Int])
splitByMod2 [] = ([], [])
splitByMod2 (x:xs)
| odd x = ([x], []) `mappend` splitByMod2 xs
| even x = ([], [x]) `mappend` splitByMod2 xs
| otherwise = error "This cannot happen"
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