recursive unpacking of a list through function signatures - sml

I'm trying to write a function in sml which 'unpacks' a nest list of arbitrary depth. For example unpack [[[1,2]]] should yield [1,2]. I 'm trying something like :
fun unpack xs = if nestedp (xs) then unpack (hd xs) else xs;
with
fun nestedp [_] = true
| nestedp _ = false;
sml doesn't like unpack defined this way because it infers that the type of unpack as 'a list -> 'a . The return of the call to hd is passed back into unpack but it now doesn't 'see' a list but a single variable.
Is it possible to unpack a nested list this way at all ?

You cannot do this for the built in list type, as you wouldn't be able to get the types to match up.
For instance, one might think it'd be possible with a function of type 'a list list -> 'a list, and then applying it recursively until it reaches a base case of a non-nested list. You would, however, not be able to detect the base case in any way, leaving your types mismatched.
You could, however, do it if you created your own list type:
datatype 'a nestableList = Cons of 'a * 'a nestableList
| NCons of 'a nestableList * 'a nestableList
| Nil;
Here, Cons and Nil would work the same as :: and [], while NCons would allow for nested list building.
As an example:
(* The list [[1, 2], [[3], [4, 5, 6]]] *)
val nlist = NCons(
Cons(1, Cons(2, Nil)),
NCons(
NCons(
Cons(3, Nil),
Cons(4, Cons(5, Cons(6, Nil)))
),
Nil
)
);
You could then flatten this nested list type like this:
fun flatten nls =
let
fun flatten_ Nil = []
| flatten_ (NCons(head, tail)) = flatten head # flatten tail
| flatten_ ( Cons(head, tail)) = head :: flatten tail
in
flatten_ nls
end;
Which then could be used like this
val flattenedNlist = flatten nlist; (* Yields [1, 2, 3, 4, 5, 6] *)
Here I have it yield a regular list, but it could easily be changed to return a list of the same type instead.

Related

Can I simplify this recursive concat function using List.fold_left?

I have created a working solution for concat, but I feel that I can reduce this using List.fold_lift.
Here is my current code:
let rec concat (lists : 'a list list) : 'a list =
match lists with
| [] -> []
| hd :: tl -> hd # concat tl ;;
Here is what I have tried:
let concat (lists : 'a list list) : 'a list =
List.fold_left # lists ;;
This gives me the error: This expression has type 'a list list but an expression was expected of type
'a list
I think this is because the return value of list.fold_left gives us a list, but we are feeding it a list of lists so it then returns a list of lists again. How can I get around this without matching?
I was also playing around with List.map but with no luck so far:
let concat (lists : 'a list list) : 'a list =
List.map (fun x -> List.fold_left # x) lists ;;
Consider the type signature of List.fold_left:
('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
List.fold_left takes three arguments.
A function.
An initial value.
A list to iterate over.
List.fold_left # lists
You're making two mistakes.
First off, this parses as (List.fold_left) # (lists).
You're looking for List.fold_left (#) lists. But that's still not quite right, because...
You're only passing two arguments, with lists being the initial value, while List.fold_left expects three.
I think that you're looking for something like:
let concat lists = List.fold_left (#) [] lists
Demonstrated:
utop # let concat lists = List.fold_left (#) [] lists in
concat [[1;2;3]; [4;5;6]; [7;8;9]];;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]
It is possible to write concat as fold_left while avoiding quadractic complexity by switching temporarily to different representation of list
If I have a list l, I can easily lift into an append function:
let to_append l = fun new_list -> l # new_list
I can also get back a list from an append function with
let to_list append = append []
And since for any list l, I have to_list ## to_append l = l, this means that the to_append is one-to-one: it does not lose any information.
Moreover concatenating two appends functions is exactly function composition
let append_concat f g l = f (g l)
Since we are not building yet any concrete list, append_concat has a constant cost (we are delaying the time complexity to the moment where we will call the append function).
We can use this better behavior of append_concat to write a linear concat' function that maps a list of lists to an append function:
let concat' l =
List.fold_left
(fun append l -> append_concat append (to_append l))
(to_append [] (* aka Fun.id *))
l
Note that this concat' is not yet building a list, it is building a closure which records the list of append functions to call later.
Building concat from concat' is then a matter of transforming back my append function to a list:
let concat l = to_list (concat' l)
And it is the call of to_list which will have a time complexity equal to the size of the final list.
To check that we got the right complexity, we can test that flattening the following list
let test =
List.init 1_000_000
(fun i ->
List.init 4 (fun k -> k + 4 * i)
)
(* this is [[0;1;2;3]; [4;5;6;7]; ... [...; 3_999_999]] *)
with
let flattened = concat test
is nearly instant.

Is there a way to multiply elements in list of pairs

Hello I'm trying to write a program in OCaml and was wondering if there is a way to get from list of pairs : [(1,2);(2,3);(3;5)] to a list where pairs are multiplied [2;6;15] this is what i have tried but it's giving me Exception: Failure "hd"
let rec mul l=
let x=(List.hd l) and y=(List.tl l) in
((fst x)*(snd x))::(mul y);;
mul [(3, 5); (3, 4); (3, 3);];;
What you want essentially is List.map (uncurry ( * )).
# let uncurry f (a, b) = f a b;;
val uncurry : ('a -> 'b -> 'c) -> 'a * 'b -> 'c = <fun>
# List.map (uncurry ( * )) [(3, 5); (3, 4); (3, 3);];;
- : int list = [15; 12; 9]
(uncurry is a basic FP function, but unfortunately it isn't defined in OCaml's fairly sparse standard library. But as you can see the definition is straightforward.)
To be honest, I think there must be simpler methods. Specifically, you have a list of n elements which are pairs (so a list of type (int * int) list) and you want to get a list of the same size, but which is the result of multiplying the two members of the pair. So, going from an (int * int) list to an int list.
As the objective is to preserve the size of the list, you can rephrase the statement by saying "I would like to apply a function on each element of my list". It is possible to do this manually, using, for example, pattern matching (which makes it possible to be explicit about the treatment of the empty list):
let rec mult my_list =
match my_list with
| [] -> (* case if my list is empty *)
[] (* The process is done! *)
| (a, b) :: tail -> (* if I have, at least, one element)
(a * b) :: (mult tail)
But generally, applying a function to each element of a list and preserving its size is called "mapping" (roughly), and fortunately there is a function in the standard OCaml library which allows this, and it is called, logically: List.map, here is its type: val map : ('a -> 'b) -> 'a list -> 'b list which could be translated as: give me a function which goes from 'a to 'b, a list of 'a and I can produce a list of 'b for you.
Here, we would like to be able to apply a function that goes from (int * int) -> int, for example: let prod (x, y) = x * y. So let's try to reimplement mult in terms of map:
let mult my_list =
let prod (x, y) = x * y in
List.map prod my_list
And voila, the pattern captured in the first purpose is exactly the idea behind List.map, for each element of a list, I apply a function and I keep the result of the function application.
Here is a working solution with the least amount of modification to your original code:
let rec mul l =
match l with
| [] -> [] (* <-- Deal with the base case *)
| _ -> (* Same as before --> *)
let x = (List.hd l) and y = (List.tl l) in
((fst x)*(snd x))::(mul y);;
Note that we just need to consider that happens when the list is empty, and we do that by matching on the list. The recursive case stays the same.

Int lists in functions

Does this function take two int lists "x and y" and return an int list of y-x?
let rec fun4 (l: int list) :int list =
begin match l with | [] -> []
| [_] -> []
| x::y::rest -> (y-x)::(fun4 (y::rest))
end
A list is defined as a recursive type:
type 'a list =
| [] of 'a list (* the empty case *)
| ( :: ) of 'a * 'a list
So you basically have two constructors: [] which is the empty list, and x :: other_list which is a list with x as head and other_list as tail. The use of these constructors makes it easy to define a list: [0; 1; 2; 3] is exactly the same of 0 :: 1 :: 2 :: 3 and of (::) (0, (::) (1, (::) (2, (::) (3, [])))) (which is not very pleasant to read).
Recursive algebraic types, here we have the conjunction of sums ([] and (::)) and products (('a * 'a list)), combined with pattern matching make it possible to describe all sorts of common data structures, as well as their functions for consuming, modifying etc.
In your example, you use pattern matching to deconstruct the list:
let rec fun4 my_list =
match my_list with
(* if my list is empty, I can't process the function so
I return the empty list *)
| [] -> []
(* if my list my list has only one element, I can't process the function
so, like in the previouse case, I return the empty list *)
| [ _ ] -> []
(* Here is the last case of the function, If I almost have two elements in the
list. Remember that empty list is also a list ! *)
| x :: y :: rest -> (y - x) :: (fun4 (y :: rest))
As you can see, Recursives Algebraic data types coupled with pattern matching are a powerful for describing data structures (like list but also many others) and for writing function that use those data structures.

ocaml 'a list list function tuples

let sample_table4 = [
[["11"];["21"];["31"];["41"]];
[["12"];["22"];["32"]];
[["13"];["23"]];
[["14"]]];;
This is where I'm stuck with writing a function to get one of these numbers
let tgvc (pos, table) =
match pos with
|[] -> []
|i::[j] -> List.nth (List.nth table (j-1)) (i-1)
|i::_ -> []
;;
val tgvc : int list * 'a list list list -> 'a list = <fun>
I'm supposed to get this signature
tgvc ([3;2],sample_table4);;
val tgvc : int list * ’a list list -> ’a = <fun>
-: string list = ["32"]
What's missing in the function?
I'm sure it has to be recursive now.
Even though it computes the right answer, it's not the right method. The ->[ ] is what's getting me
let rec tgvc (pos, table) = function
|_,[] -> []
|[i;1], h::_ -> List.nth h (i-1)
|[i;j], _::t -> tgvc ([i;j-1], t)
|_ -> []
|[i;j], _::t -> tgvc ([i;j-1], t)
^^^^^^^^^^^^^^^^^
Error: This expression has type int list * 'a list list list -> 'a list
but an expression was expected of type 'a list
What's missing in the function?
A lot of things. Your function simply returns one of many lists of initial input. You don't even use i indice.
I suggest you to think what your function need to do for the given input:
[i; 1], h::_ - you are "in front" of the desirable list
[i; j], _::t - not desirable list yet (some recursion maybe?)
_, [] - empty table
_ - everything else
Edit
You have two problems with your last implementation. First of all in your first and last branches you return [], I guess you would like to exit with an error, so you can throw an exception (via failwith for example). The second problem is actually in the first line: get_table_values_cell (pos, table) = function, it means that you define get_table_values_cell as function with two arguments, you give one explicitly ((pos, table)) and the second is introduced by function keyword. So all you need is to pick only one: get_table_values_cell = function

Combine Lists with Same Heads in a 2D List (OCaml)

I'm working with a list of lists in OCaml, and I'm trying to write a function that combines all of the lists that share the same head. This is what I have so far, and I make use of the List.hd built-in function, but not surprisingly, I'm getting the failure "hd" error:
let rec combineSameHead list nlist = match list with
| [] -> []#nlist
| h::t -> if List.hd h = List.hd (List.hd t)
then combineSameHead t nlist#uniq(h#(List.hd t))
else combineSameHead t nlist#h;;
So for example, if I have this list:
[[Sentence; Quiet]; [Sentence; Grunt]; [Sentence; Shout]]
I want to combine it into:
[[Sentence; Quiet; Grunt; Shout]]
The function uniq I wrote just removes all duplicates within a list. Please let me know how I would go about completing this. Thanks in advance!
For one thing, I generally avoid functions like List.hd, as pattern maching is usually clearer and less error-prone. In this case, your if can be replaced with guarded patterns (a when clause after the pattern). I think what is happening to cause your error is that your code fails when t is []; guarded patterns help avoid this by making the cases more explicit. So, you can do (x::xs)::(y::ys)::t when x = y as a clause in your match expression to check that the heads of the first two elements of the list are the same. It's not uncommon in OCaml to have several successive patterns which are identical except for guards.
Further things: you don't need []#nlist - it's the same as just writing nlist.
Also, it looks like your nlist#h and similar expressions are trying to concatenate lists before passing them to the recursive call; in OCaml, however, function application binds more tightly than any operator, so it actually appends the result of the recursive call to h.
I don't, off-hand, have a correct version of the function. But I would start by writing it with guarded patterns, and then see how far that gets you in working it out.
Your intended operation has a simple recursive description: recursively process the tail of your list, then perform an "insert" operation with the head which looks for a list that begins with the same head and, if found, inserts all elements but the head, and otherwise appends it at the end. You can then reverse the result to get your intended list of list.
In OCaml, this algorithm would look like this:
let process list =
let rec insert (head,tail) = function
| [] -> head :: tail
| h :: t ->
match h with
| hh :: tt when hh = head -> (hh :: (tail # t)) :: t
| _ -> h :: insert (head,tail) t
in
let rec aux = function
| [] -> []
| [] :: t -> aux t
| (head :: tail) :: t -> insert (head,tail) (aux t)
in
List.rev (aux list)
Consider using a Map or a hash table to keep track of the heads and the elements found for each head. The nlist auxiliary list isn't very helpful if lists with the same heads aren't adjacent, as in this example:
# combineSameHead [["A"; "a0"; "a1"]; ["B"; "b0"]; ["A"; "a2"]]
- : list (list string) = [["A"; "a0"; "a1"; "a2"]; ["B"; "b0"]]
I probably would have done something along the lines of what antonakos suggested. It would totally avoid the O(n) cost of searching in a list. You may also find that using a StringSet.t StringMap.t be easier on further processing. Of course, readability is paramount, and I still find this hold under that criteria.
module OrderedString =
struct
type t = string
let compare = Pervasives.compare
end
module StringMap = Map.Make (OrderedString)
module StringSet = Set.Make (OrderedString)
let merge_same_heads lsts =
let add_single map = function
| hd::tl when StringMap.mem hd map ->
let set = StringMap.find hd map in
let set = List.fold_right StringSet.add tl set in
StringMap.add hd set map
| hd::tl ->
let set = List.fold_right StringSet.add tl StringSet.empty in
StringMap.add hd set map
| [] ->
map
in
let map = List.fold_left add_single StringMap.empty lsts in
StringMap.fold (fun k v acc-> (k::(StringSet.elements v))::acc) map []
You can do a lot just using the standard library:
(* compares the head of a list to a supplied value. Used to partition a lists of lists *)
let partPred x = function h::_ -> h = x
| _ -> false
let rec combineHeads = function [] -> []
| []::t -> combineHeads t (* skip empty lists *)
| (hh::_ as h)::t -> let r, l = List.partition (partPred hh) t in (* split into lists with the same head as the first, and lists with different heads *)
(List.fold_left (fun x y -> x # (List.tl y)) h r)::(combineHeads l) (* combine all the lists with the same head, then recurse on the remaining lists *)
combineHeads [[1;2;3];[1;4;5;];[2;3;4];[1];[1;5;7];[2;5];[3;4;6]];;
- : int list list = [[1; 2; 3; 4; 5; 5; 7]; [2; 3; 4; 5]; [3; 4; 6]]
This won't be fast (partition, fold_left and concat are all O(n)) however.