Show Multiple occurrences of items in a list, sml - sml

I'm trying to show the indices of all multiple occurrences for an element in a list.
in standard ml.
but my code show the empty list :(
this is my code:
fun index(item, xs,ys) =
let
fun index'(m, nil , ys) = (
SOME (ys) )
| index'(m, x::xr , ys) = if x = item then(
(ys # [m]);
index'(m + 1, xr , ys)
)
else index'(m + 1, xr,ys)
in
index'(0, xs , ys)
end;
index(1,[1,2,1,4,5,1],[]);
can you help me?

First things first:
index should take two arguments; the element to look for and the list to look for it in.
The accumulation parameter belongs to the helper function.
It is meaningless to always produce SOME of something and never NONE.
Let's fix these first.
fun index (item, xs) =
let
fun index'(m, nil , ys) = ys
| index'(m, x::xr, ys) = if x = item then(
(ys # [m]);
index'(m + 1, xr , ys)
)
else index'(m + 1, xr,ys)
in
index'(0, xs, [])
end;
Now you don't need to pass the extra accumulator parameter when you use index.
It's also impossible to start with something other than [].
Your next, and main, problem is
(ys # [m]);
index'(m + 1, xr , ys)
which first creates the list ys # [m], immediately throws it away, and then produces as its result index'(m + 1, xr , ys), which is exactly what the else branch does.
That is, the conditional is equivalent to
if x = item
then index'(m + 1, xr, ys)
else index'(m + 1, xr, ys)
and thus, index' is equivalent to
fun index'(m, nil, ys) = ys
| index'(m, x::xr, ys) = index'(m + 1, xr, ys)
Since you always pass the original ys along, and it is [] to start with, the result is always [].
What you need to do is to pass the extended list to the recursion, so it can become the result when the recursion terminates.
Renaming the accumulator ys to make its purpose clearer:
fun index (item, xs) =
let
fun index'(i, nil, accumulator) = accumulator
| index'(i, x::xr, accumulator) = if x = item
then index' (i + 1, xr, accumulator # [i])
else index' (i + 1, xr, accumulator)
in
index'(0, xs, [])
end;
This is inefficient, due to the repeated appending of an element to the back of a list.
It is very common to accumulate in reverse, and correct it when you're done.
(This "feels" inefficient, but it isn't.)
fun index (item, xs) =
let
fun index'(i, nil, accumulator) = List.reverse accumulator
| index'(i, x::xr, accumulator) = if x = item
then index' (i + 1, xr, i::accumulator)
else index' (i + 1, xr, accumulator)
in
index'(0, xs, [])
end;

Related

how to stop a recursive function in this case (SML)

fun p(L) =
[L] # p( tl(L) # [hd(L)] );
If L is [1,2,3] then I want to have a [ [1,2,3], [2,3,1], [3,1,2] ].
Since every time I append the first num to the end, then if L = [] then [] doesn't work here.
How to stop the function once it has the three lists?
You can have a parameter x in the function to keep track of how many levels deep in the recursion you are.
fun p(L, x) =
if x < length(L) then [L] # p(tl(L) # [hd(L)], x+1)
else [];
Then call the function with x=0.
p([1, 2, 3], 0)
And if you don't like the extra parameter, then as you probably know you can define another function and make it equal to the p function with the parameter forced to 0.
fun p0(L) = p(L, 0);
p0([1, 2, 3]); (* same result as p([1, 2, 3], 0); *)
Let me show some more implementation variants.
First of all, let's define an auxiliary function, which rotates a list 1 position to the left:
(* operates on non-empty lists only *)
fun rot1_left (h :: tl) = tl # [h]
Then the p function could be defined as follows:
fun p xs =
let
(* returns reversed result *)
fun loop [] _ _ = []
| loop xs n res =
if n = 0
then res
else loop (rot1_left xs) (n-1) (xs :: res)
in
List.rev (loop xs (length xs) [])
end
It's usually better (performance-wise) to add new elements at the beginning of the list and then reverse the resulting list once, than to append to the end many times. Note: this version does one spurious rotate at the end and I could have optimized it out, but didn't, to make code more clear.
We have calculated the length of the given list to make its rotated "copies", but we don't have to traverse xs beforehand, we can do it as we rotate it. So, we can use xs as a kind of counter, recursively calling the loop helper function on the tail of the xs list.
fun p xs =
let
(* returns reversed result *)
fun loop [] _ _ = []
| loop xs [] res = res
| loop xs (_::tl) res =
loop (rot1_left xs) tl (xs :: res)
in
List.rev (loop xs xs [])
end
Having done that, we are now closer to implementing p as a foldl function:
fun p xs =
(List.rev o #1)
(List.foldl
(fn (_, (res, rot)) => (rot::res, rot1_left rot))
([], xs)
xs)
The second argument to the List.foldl function is our "accumulator", which is represented here as a pair of the current (partial) result as in the previous implementations and the current rotated list. That explains (List.rev o #1) part: we need to take the first component of the accumulator and reverse it. And as for the ([], xs) part -- the current result is empty at the beginning (hence []) and we start rotating the initial xs list. Also, the _ in (_, (res, rot)) means the current element of the given xs, which we don't care about, since it just serves as a counter (see the prev. variant).
Note: o stands for function composition in Standard ML.

Cut a list by index n in F#

Trying to write a recursive function that will cut a list by n. Then return 2 lists. So if I pass
cut(2, [5;10;4;2;7]);;
val it : int list * int list = ([5; 10], [4; 2; 7])
I would like to get something like that.
let rec cut (n, xs) =
match n, xs with
| 0, xt -> (n, xs)
| n, x::xt -> cut(n, xt), xs;;
Please help.
I'll ad an explanation of #MisterMetaphors recursive function.
The cut function isn't recursive but aux is, it works by counting down from n and removing elements from the head of the list passed to cut.
Say you call cut like this cut 2 [ 3; 4; 5; 7; 8 ]. aux is a pattern matching function taking three arguments: n, partition 1, partition 2. Partition 1 starts out with being an empty list and partition 2 starts out with being the full list passed to cut.
First time aux will match the second clause, then it'll call itself with arguments (1, [3], [4; 5; 7; 8]). Next time it'll also match second clause, now it calls itself with (0, [4; 3], [5; 7; 8]). Third and final time it matches first clause (n=0) and it will return a tuple containing xs and ys.
Notice however that the elements of the xs is in reverse order since each element was prepended (using cons operator ::). The reason this is done is because it's an O(1) operation compared to the append operator # which is O(n) on the left side.
Since xs is in reverse order the last expression in the function is a reversal of xs.
An alternative and slightly short definition could be:
let cut n xs =
let rec aux = function
| 0, xs, ys -> List.rev xs, ys
| n, xs, y :: ys -> aux (n - 1, y :: xs, ys)
| _ -> failwith "invalid arguments"
aux (n, [], xs)
It's probably better to combine built-in functions on lists or sequences to achieve this:
let cut' (n, xs) =
Seq.take n xs, Seq.skip n xs
Recursively, your function can be defined like so:
let cut (n, xs) =
let rec aux = function
| 0, xs, ys -> xs, ys
| n, xs, y :: ys -> aux (n - 1, y :: xs, ys)
| _ -> failwith "invalid arguments"
let l, r = aux (n, [], xs)
(List.rev l, r)

Returning the list of elements occurring in just one list - SML

If L1 = [1,2,3,4,5] and L2 [4,5,6,7,8], I want to return [1,2,3,5,7,8] which are the elements occurring in one list only. I already wrote a function returning the list of items occurring in both lists.
fun exists x nil = false | exists x (h::t) = (x = h) orelse (exists x t);
fun listAnd _ [] = []
| listAnd [] _ = []
| listAnd (x::xs) ys = if exists x ys then x::(listAnd xs ys)
else listAnd xs ys
The list I am looking for should be given by L1#L2 - (ListAnd L1 L2). I also found functions that delete an element and remove Duplicates. I made several attempts at changing the remDup function slightly so that it will leave no trace of ANY items that occured more than once. Could not get it working. I am not sure how to use and combine all those functions to make it work.
fun delete A nil = nil
| delete A (B::R) = if (A=B) then (delete A R) else (B::(delete A R));
fun remDups nil = nil
| remDups (A::R) = (A::(remDups (delete A R)));
If there is a diff function where diff xs ys returns all elements in xs but not in ys, you can implement listOr function easily:
fun listOr xs ys = diff (xs#ys) (listAnd xs ys)
The diff function can be written similarly to listAnd:
fun diff xs [] = xs
| diff [] _ = []
| diff (x::xs) ys = if exists x ys
then diff xs ys
else x::(diff xs ys)

Split list into two

I would like to implement a function that takes as input a size n and a list. This function will cut the list into two lists, one of size n and the rest in another list. I am new to this language and have a hard time learning the syntax.
The main problem I have is that is finding a way to express a size of the list without using any loops or mutable variables.
Can anyone give a me some pointers?
Let's start with the function's type signature. Since it gets n and a list as arguments and returns a pair of lists, you have a function split:
val split : int -> 'a list -> 'a list * 'a list
Here is one approach to implement this function:
let split n xs =
let rec splitUtil n xs acc =
match xs with
| [] -> List.rev acc, []
| _ when n = 0 -> List.rev acc, xs
| x::xs' -> splitUtil (n-1) xs' (x::acc)
splitUtil n xs []
The idea is using an accumulator acc to hold elements you have traversed and decreasing n a long the way. Because elements are prepended to acc, in the end you have to reverse it to get the correct order.
The function has two base cases to terminate:
There's no element left to traverse (xs = [] at that point).
You have gone through the first n elements of the list (n decreases to 0 at that time).
Here is a short illustration of how split computes the result:
split 2 [1; 2; 3] // call the auxiliary function splitUtil
~> splitUtil 2 [1; 2; 3] [] // match the 3rd case of x::xs'
~> splitUtil 1 [2; 3] [1] // match the 3rd case of x::xs'
~> splitUtil 0 [3] [2; 1] // match the 2nd case of n = 0 (base case)
~> List.rev [2; 1], [3] // call List.rev on acc
~> [1; 2], [3]
let split n list =
let rec not_a_loop xs = function
| (0, ys) | (_, ([] as ys)) -> (List.rev xs), ys
| (n, x::ys) -> not_a_loop (x::xs) (n-1, ys)
not_a_loop [] (n, list)
New solution - splitAt is now built into List and Array. See commit around 2014 on github. I noticed this today while using F# in VS.2015
Now you can simply do this...
let splitList n list =
List.splitAt n list
And as you might expect the signature is...
n: int -> list: 'a list -> 'a list * 'a list
Example usage:
let (firstThree, remainder) = [1;2;3;4;5] |> (splitList 3)
printfn "firstThree %A" firstThree
printfn "remainder %A" remainder
Output:
firstThree [1; 2; 3]
remainder [4; 5]
Github for those interested: https://github.com/dsyme/visualfsharp/commit/1fc647986f79d20f58978b3980e2da5a1e9b8a7d
One more way, using fold:
let biApply f (a, b) = (f a, f b)
let splitAt n list =
let splitter ((xs, ys), n') c =
if n' < n then
((c :: xs, ys), n' + 1)
else
((xs, c :: ys), n' + 1)
List.fold splitter (([], []), 0) list
|> fst
|> biApply List.rev
Here is a great series on folds than you can follow to learn more on the topic.

Ocaml noobie Q -- how to use accumulating parameters?

I'm trying to learn Ocaml by working on Problem 18 from Project Euler. I know what I want to do, I just can't figure out how to do it.
I've got three lists:
let list1 = [1;2;3;4;5];;
let list2 = [ 6;7;8;9];;
let line = [9999];;
I want to add the numbers list2 to the max adjacent number in list1, IOW I would add 6+2, 7+3, 8+4 and 9+5 to get a list [8;10;12;14]. The list line[] is a dummy variable.
Here's my third try:
let rec meld3 l1 l2 accum =
if List.length l2 = 1 then
List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))]
else
(
List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))];
meld3 (tl l1) (tl l2) accum ;
)
;;
let fu = meld3 list1 list2 line ;;
List.iter print_int fu;;
After running this, I would expect line = [9999;8;10;12;14] but instead line = [9999].
OTOH, fu prints out as [999914].
When I step through the code, the code is executing as I expect, but nothing is changing; the accum in the else block is never modified.
I just don't get this language. Can anyone advise?
OK, let's break down your code. Here's your original.
let rec meld3 l1 l2 accum =
if List.length l2 = 1 then
List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))]
else
(
List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))];
meld3 (tl l1) (tl l2) accum ;
)
The first thing I'm going to do is rewrite it so a Caml programmer will understand it, without changing any of the computations. Primarily this means using pattern matching instead of hd and tl. This transformation is not trivial; it's important to simplify the list manipulation to make it easier to identify the problem with the code. It also makes it more obvious that this function fails if l2 is empty.
let rec meld3 l1 l2 accum = match l1, l2 with
| x1::x2::xs, [y] -> (* here the length of l2 is exactly 1 *)
List.append accum [ y + max x1 x2 ]
| x1::x2::xs, y::ys -> (* here the length of l2 is at least 1 *)
( List.append accum [ y + max x1 x2 ]
; meld3 (x2::xs) ys accum
)
Now I think the key to your difficulty is the understanding of the semicolon operator. If I write (e1; e2), the semantics is that e1 is evaluated for side effect (think printf) and then the result of e1 is thrown away. I think what you want instead is for the result of e1 to become the new value of accum for the recursive call. So instead of throwing away e1, we make it a parameter (this is the key step where the computation actually changes):
let rec meld3 l1 l2 accum = match l1, l2 with
| x1::x2::xs, [y] -> (* here the length of l2 is exactly 1 *)
List.append accum [ y + max x1 x2 ]
| x1::x2::xs, y::ys -> (* here the length of l2 is at least 1 *)
(
meld3 (x2::xs) ys (List.append accum [ y + max x1 x2 ])
)
Next step is to observe that we've violated the Don't Repeat Yourself principle, and we can fix that by making the base case where l2 is empty:
let rec meld3 l1 l2 accum = match l1, l2 with
| x1::x2::xs, [] -> (* here the length of l2 is 0 *)
accum
| x1::x2::xs, y::ys -> (* here the length of l2 is at least 1 *)
(
meld3 (x2::xs) ys (List.append accum [ y + max x1 x2 ])
)
We then clean up a bit:
let rec meld3 l1 l2 accum = match l1, l2 with
| _, [] -> accum
| x1::x2::xs, y::ys -> meld3 (x2::xs) ys (List.append accum [ y + max x1 x2 ])
Finally, the repeated calls to append make the code quadratic. This is a classic problem with accumulating parameters and has a classic solution: accumulate the answer list in reverse order:
let rec meld3 l1 l2 accum' = match l1, l2 with
| _, [] -> List.rev accum'
| x1::x2::xs, y::ys -> meld3 (x2::xs) ys (y + max x1 x2 :: accum')
I've changed the name accum to accum'; the prime is conventional for a list in reverse order. This last version is the only version I have compiled, and I haven't tested any of the code. (I did test the code in my other answer).
I hope this answer is more helpful.
Well, I think you haven't grasped the essence of functional programming: instead of calling List.append and throwing the value away, you need to pass that value as the parameter accum to the recursive call.
I would tackle this problem by decoupling the triangle geometry from the arithmetic. The first function takes two lists (rows of the triangle) and produces a new list of triples, each containing and element plus that element's left and right child. Then a simple map produces a list containing the sum of each element with its greater child:
(* function to merge a list l of length N with a list l' of length N+1,
such that each element of the merged lists consists of a triple
(l[i], l'[i], l'[i+1])
*)
let rec merge_rows l l' = match l, l' with
| [], [last] -> [] (* correct end of list *)
| x::xs, y1::y2::ys -> (x, y1, y2) :: merge_rows xs (y2::ys)
| _ -> raise (Failure "bad length in merge_rows")
let sum_max (cur, left, right) = cur + max left right
let merge_and_sum l l' = List.map sum_max (merge_rows l l')
let list1 = [1;2;3;4;5]
let list2 = [ 6;7;8;9]
let answer = merge_and_sum list2 list1
If you are working on Euler 18, I advise you to look up "dynamic programming".