I recently started learning ocaml and am having trouble figuring out a problem.
Goal:
Given a list of integers and a function, sort the integers into equivalence classes based on the given function as lists inside another list. The order of the equivalence lists must be the same as the order given in the original list.
Update: I have decided to try and get it working without library function.
This is my code so far. It compiles but does not run. Any help with syntax would be appreciated.
let buckets f lst =
let rec helpfunction f lst newlist =
match lst with
| [] ->newlist
| h::t -> match newlist with
| [] -> helpfunction f lst [h]@newlist
| [a]::_ -> if f h a
then helpfunction f t [a::h]@newlist
else helpfunction f t ([a]::[h]@mylist
IMPORTANT: this is a homework question, so I am not looking for the code pasted for me. Im trying to logic through it on my home with a bit of help with the overall thought-process and syntax. Once I get it working I would to work on making it more efficient
Well, let's try to solve the task without doing it actually :)
Roughly speaking, the algorithm looks as follows:
Take the integer
xfrom the source listIf the target list of lists (each of them contains integers of the same equivalence class) contains the list of the appropriate equivalence class add
xto this listOtherwise, create a new equivalence class list containing a single value (
[x]) and add it to the target listRepeat 1-3 for the other integers in the target list.
(1), (3) and (4) seems to be quite trivial to implement.
The challenges are how to implement (2) and how to do it efficiently :)
"Target list contains the list that..." can be rephrased as "there exists a list
lstin a target list such as..." - this gives us a strong hint thatList.existscan be somehow used here. What to test is also more or less clear: each member of the same equivalence class list are equivalent by definition, so we can take just the head and compare it withxusingp.The question is how to add an integer to a list within another list. Lists are immutable, so we cannot just drop it there... But we can take the target list and transform, or fold it into another one. I bet you got the hint:
List.fold_leftis another piece of the puzzle.So, summarizing all this we can come to the following "more precise" algorithm
Start from the empty target list
resTake an integer
xfrom the source listlUse
List.existsto check if there is a listlstinressuch as for its headhp x h = trueIf yes, use
List.fold_leftto transform the currentresinto a new one, wherelstreplaced withx::lstand all other equivalence class lists are copied as isIf no, introduce a new equivalence class (add
[x]tores)Repeat 2-5 for the next integer in the source list until it is empty.
The implementation that (almost) literally follows this algorithm is relatively simple. But it will be not very efficient because
existsandfoldwill iterate over the same list twice doing literally the same check. With some tweaks, it should be possible to make it in a single run, but this non-efficient one should be good enough as the starting point...