Ocaml function parsing list of lists - list

I am trying to build a function in Ocaml which parses a list of lists, eg from [[0;1];[3;4;8]] to [0;1;3;4;8]. I tried to do something like:
#let rec parse listoflists=
match listoflists with
[[]]->[]
|[h::t]->h::parse [t];;
but it doesn't work... I also need an explanation, because I don't understand how the lists of lists actually work...
I don't have to use the Ocaml library functions.

If you can understand a list, then I claim you already know about lists of lists. This is the beauty of recursion.
The only real difficulty (as I see it) is keeping track of which list you're talking about. Your code needs to work with the list of lists itself, which consists of one list (call it h) followed by some other lists. It also needs to work with the list h, which consists of some element (call it hh) followed by some other elements.
It seems to me there are three interesting cases: (a) the list of lists is empty; (b) the first element of the list of lists h is empty (c) neither the list of lists nor h is empty.
You are not handling all three of these cases. That's one way to see that your code probably wouldn't work.
Here is a match that matches the three cases, which might help a little:
match listoflists with
| [] -> ... (* List of lists is empty *)
| [] :: t -> ... (* First list h is empty *)
| (hh :: ht) :: t -> ... (* Neither is empty *)

Related

Pack consecutive duplicates of list elements into sublists in Ocaml

I found this problem in the website 99 problems in ocaml. After some thinking I solved it by breaking the problem into a few smaller subproblems. Here is my code:
let rec frequency x l=
match l with
|[]-> 0
|h::t-> if x=[h] then 1+(frequency x t)
else frequency x t
;;
let rec expand x n=
match n with
|0->[]
|1-> x
|_-> (expand x (n-1)) # x
;;
let rec deduct a b=
match b with
|[]-> []
|h::t -> if a=[h] then (deduct a t)
else [h]# (deduct a t)
;;
let rec pack l=
match l with
|[]-> []
|h::t -> [(expand [h] (frequency [h] l))]# (pack (deduct [h] t))
;;
It is rather clear that this implementation is overkill, as I have to count the frequency of every element in the list, expand this and remove the identical elements from the list, then repeat the procedure. The algorithm complexity is about O(N*(N+N+N))=O(N^2) and would not work with large lists, even though it achieved the required purpose. I tried to read the official solution on the website, which says:
# let pack list =
let rec aux current acc = function
| [] -> [] (* Can only be reached if original list is empty *)
| [x] -> (x :: current) :: acc
| a :: (b :: _ as t) ->
if a = b then aux (a :: current) acc t
else aux [] ((a :: current) :: acc) t in
List.rev (aux [] [] list);;
val pack : 'a list -> 'a list list = <fun>
the code should be better as it is more concise and does the same thing. But I am confused with the use of "aux current acc" in the inside. It seems to me that the author has created a new function inside of the "pack" function and after some elaborate procedure was able to get the desired result using List.rev which reverses the list. What I do not understand is:
1) What is the point of using this, which makes the code very hard to read on first sight?
2) What is the benefit of using an accumulator and an auxiliary function inside of another function which takes 3 inputs? Did the author implicitly used tail recursion or something?
3) Is there anyway to modify the program so that it can pack all duplicates like my program?
These are questions mostly of opinion rather than fact.
1) Your code is far harder to understand, in my opinion.
2a) It's very common to use auxiliary functions in OCaml and other functional languages. You should think of it more like nested curly braces in a C-like language rather than as something strange.
2b) Yes, the code is using tail recursion, which yours doesn't. You might try giving your code a list of (say) 200,000 distinct elements. Then try the same with the official solution. You might try determining the longest list of distinct values your code can handle, then try timing the two different implementations for that length.
2c) In order to write a tail-recursive function, it's sometimes necessary to reverse the result at the end. This just adds a linear cost, which is often not enough to notice.
3) I suspect your code doesn't solve the problem as given. If you're only supposed to compress adjacent elements, your code doesn't do this. If you wanted to do what your code does with the official solution you could sort the list beforehand. Or you could use a map or hashtable to keep counts.
Generally speaking, the official solution is far better than yours in many ways. Again, you're asking for an opinion and this is mine.
Update
The official solution uses an auxiliary function named aux that takes three parameters: the currently accumulated sublist (some number of repetitions of the same value), the currently accumulated result (in reverse order), and the remaining input to be processed.
The invariant is that all the values in the first parameter (named current) are the same as the head value of the unprocessed list. Initially this is true because current is empty.
The function looks at the first two elements of the unprocessed list. If they're the same, it adds the first of them to the beginning of current and continues with the tail of the list (all but the first). If they're different, it wants to start accumulating a different value in current. It does this by adding current (with the one extra value added to the front) to the accumulated result, then continuing to process the tail with an empty value for current. Note that both of these maintain the invariant.

Getting all indices of a value

Im trying to create a haskell function where all the indices of an occurence of a value in a list are returned as a list, so like
indices 3 [1,2,3,3,7]
gives [2, 3] as output. I am very new to Haskell and couldnt find something useful. I tried using filter, but all i got working is getting a list of [3, 3] but not the actual indices. It would be cool if you could give me a little hint.
This is a pretty common pattern in functional programming, sometimes called decorate-process-undecorate. The idea is that you want to attach some extra information to each of the elements in your list, filter using a slightly altered version of the filter you would have done normally, then strip that extra information away.
indicies n = undecorate . filter predicate . decorate where
decorate = ...
predicate = ...
undecodate = ...
When trying to code decorate I suggest taking a look at the function zip:
zip :: [a] -> [b] -> [(a, b)]
Consider its effect on infinite lists, too, such as repeat 1 or [1,3,...]. When trying to code undecorate you'll likely want to map:
map :: (a -> b) -> [a] -> [b]
Finally, don't worry about the efficiency of this process. In a strict language, decorate-filter-undecorate might require 3 traversals of the list. In a non-strict language like Haskell the compiler will automatically merge the 3 inner loops into a single one.

ocaml sum of two lists with different length

I tried to add two lists with different lengths using this:
let sumList(a,b) = match a,b with
|[],_ -> []
|(x::xs,y::ys)-> (x + y)::diffList(xs,ys)
It returns Unbound value sumList. Is it possible to do this as in Haskell: zipWith(+) a b.
Possibly the actual error is "Unbound value diffList", since you don't define diffList in your code.
If this is a transcription error, then the next problem is that you need to declare sumList as a recursive function: let rec sumList (a, b) = ....
Your pattern match is not exhaustive. It fails if the first list is longer.
The Haskell zipWith is friendlier than the OCaml List.map2, which requires the lists to be the same length. I don't think there's anything so friendly in the OCaml standard library.

Compare int with List SML

I am just starting to learn SML and having issues with my code. I want to compare an int with List of ints and return a list of numbers less than my int
fun less(e, L): L =
if L = [] then []
else (hd[L] < e :: less tl(hd))
I want to return a list of all numbers less than e by comparing it to the list L. What I'm I doing wrong?
hd[L] < e :: less tl(hd)
First of all less tl(hd) is the same as just less tl hd or (less tl) hd. Writing f g(x) does not mean "apply g to x and f to the result". For that you'd need to write f (g x). In general putting parentheses around atomic expressions won't change anything and by leaving out the space before the opening parentheses, you make the syntax look like something it's not, so you should avoid that.
Then tl hd simply doesn't make much sense as hd is a function and tl expects a list. You probably meant to apply tl to L, not to hd.
Then hd [L] takes the first element of the list [L]. [L] is a list with a single element: L. So writing hd [L] is the same thing as just writing L. You probably meant tot take the head of L. For that you'd just write hd L without the brackets.
Now the problem is that you're trying to prepend the result of (hd L) < e, which is a boolean, to the list. This will work (as in compile and run without error), but it will result in a list of booleans (which will contain a true for any element less than e and a false for any other element). That's not what you said you wanted. To get what you want, you should have an if which appends the head to the list if it is less than e and doesn't prepend anything when it's not.
Fixing these problems should make your code work as intended.
PS: Usually it's preferred to use pattern matching to find out whether a list is empty and to split a non-empty list into its head and tail. The functions hd and tl are best avoided in most circumstances and so is = []. However if you haven't covered pattern matching yet, this is fine for now.
PPS: You can do what you want much more easily and without recursion by using the filter function. But again: if you haven't covered that yet, your way is fine for now.
am i wrong is it that you didn't compare the elements. you only catered for the empty list.
something like
if e < hd L then e::less(e, (tl L))

Flattening a list of lists in OCaml

I am implementing this hoemwork functionality using Ocaml:
Not allowed to use List module
the function has type 'a list list -> 'a list
the function return a list consisting of the lists in x concatenated together (just top level of lists is concatenated, unlike List.flatten)
For example : [[1,2,3],[45]] => [1,2,3,4,5] and [[[1,2,3],[4,5]],[[6,7]]] => [[1,2,3],[4,5],[6,7]]
I am not sure where to start, can anyone give me some suggestion? Thank you
I don't see the difference between List.flatten and your function.
To answer to your question: as usual with lists, try to think about the base cases:
what do you do when you concatenate an empty list with something ?
what do you do when you concatenate a non-empty list (with a head and a tail) with something ?
Wrap everything into a pattern match, cook it for few hours, and that's done :-)
Thomas has given excellent advice. Your basic operation is going to be to append one list to another. It might help to write this function as a separate function first. It will look something like this:
let rec myappend a b =
match a with
| [] -> (* Empty list prefixed to b (easy case) *)
| ahead :: atail -> (* Recursive case *)
Armed with your own append function, you can carry out another level of recursion
to append all the top-level lists as Thomas suggests.