This is one example of code that I would imagine work work fine in a set data type implemented as a list:
fun newSet() = nilset;
fun isMember (k, x::xs) = if k = x then true else isMember (k, xs)
| isMember (k, nilset) = false;
The problem is that I cannot implement it as a list. Below is the code for the implementation of my set.
abstype ''a set = nilset | st of ''a * ''a set
How can I recursively do this and other set operations if :: is for lists? If it's not, why is this throwing exceptions? I get this when I use :::
! Type clash: pattern of type
! ''a set
! cannot have type
! ''b list
Thanks for any help.
It isn't an exception; it is a type error saying that you can't use cons constructor :: belonging to 'a list with 'a set.
Assuming that you have two constructors Nilset and Set in a recursive datatype:
datatype 'a set = Nilset | Set of 'a * 'a set
You should follow the recursive structure of your datatype to define isMember:
fun isMember (k, Set(x, xs)) = k = x orelse isMember (k, xs)
| isMember (k, Nilset) = false
Certainly, for serious use of Set, you should look into Set structure.
Related
I am trying to implement boolean disjunction. I have successfully implemented it using recursion, and for a bit of practice I am trying to do the same using List.fold_right but I am failing miserably.
let q1fold lst =
List.fold_right (fun lst acc ->
match lst with
| [] -> acc
| h::t -> if h then true else false )
Consider the type signature of List.fold_right:
# List.fold_right;;
- : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b = <fun>
Three arguments are taken. You've only passed one.
List.fold_right and List.fold_left consider an initial value and each element of the input list and runs a function on them to generate the initial value for the next iteration, returning that value at the end of the list.
What do you think the "update" and the initial values should be in the following to implement the functionality you want?
List.fold_right (fun x init -> ...) [true; false; false] ...
Note 1: I would use List.fold_left as it is tail-recursive, though for a small dataset it is unlikely to make a practical difference here.
Note 2: if h then true else false is equivalent to h.
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.
please help.
I am trying to write two non-recursive functions in OCaml (a list of lists contains elements that are lists themselves)
clear l which takes a list of lists as an argument and returns the list of lists without empty lists if there are any.
Example: clear [[2];[];[];[3;4;6];[6;5];[]]
will returns
[[2];[3;4;6];[6;5]]
sort_length l that sorts the elements of this list l according to their length. E.g. sort_length [[2];[];[3];[6;5]] returns [[];[2];[3];[6;5]]
I am only allowed to use these predefined functions: List.filter, List.sort, List.hd, List.tl, List.length and no others.
Thanks
For the second function, I have tried this so far, but I used map which is not allowed
let rec insert cmp e = function
| [] -> [e]
| h :: t as l -> if cmp e h <= 0 then e :: l else h :: insert cmp e t
let rec sort cmp = function
| [] -> []
| h :: t -> insert cmp h (sort cmp t)
let sort_length l =
let l = List.map (fun list -> List.length list, list) l in
let l = sort (fun a b -> compare (fst a) (fst b)) l in
List.map snd l;;
Thanks
As mentioned here: https://ocaml.org/api/List.html#VALfilter, List.filter returns all the elements of the list that satisfy the given predicate. So you must write a predicate that describes a list that is not empty. Another way of saying that a list is not empty is to say that "its size is greater than zero". So it would be possible to formulate clear in this way:
let clear list =
let is_not_empty l = (List.length l) > 0 in
List.filter is_not_empty list
Small edit
As mentioned by Chris Dutton, using List.length may be inefficient. Another approach would be to express is_not_empty in this way:
let is_not_empty = function
| [] -> false
| _ -> true
This approach is "better" because it does not require going through the whole list to see if it is empty or not.
For the second point, the List.sort function takes a comparison function between two elements ('a -> 'a -> int), here the comparison must act on the size of the lists.
In other words, the size of the two lists observed must be compared. One way to do this would be to use Int.compare (https://ocaml.org/api/Int.html#VALcompare) on the size of the two observed lists. For example:
let sort_length list =
let compare_length a b =
let la = List.length a in
let lb = List.length b in
Int.compare la lb
in
List.sort compare_length list
There are more concise ways of writing these two functions but these implementations should be fairly clear.
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.
I am trying to write a function that filters positive integers from a list of list of integers, returning a list of only negative integers.
For example, if I have a list of list such as [[-1; 1]; [1]; [-1;-1]] it would return [[-1]; []; [-1;-1]].
I tried to use filter and transform functions, which was in my textbook.
let rec transform (f:'a -> 'b) (l:'a list) : 'b list =
begin match l with
| [] -> []
| x::tl -> (f x)::(transform f tl)
end
and for filter, I had previously written:
let rec filter (pred: 'a -> bool) (l: 'a list) : 'a list =
begin match l with
| [] -> []
| x :: tl -> if pred x then x :: (filter pred tl) else filter pred tl
end
So, using these, I wrote
let filter_negatives (l: int list list) : int list list =
transform (fun l -> (filter(fun i -> i<0)) + l) [] l
but I'm still having trouble fully understanding anonymous functions, and I'm getting error messages which I don't know what to make of.
This function has type ('a -> 'b) -> 'a list -> 'b list
It is applied to too many arguments; maybe you forgot a `;'.
(For what it's worth this transform function is more commonly called map.)
The error message is telling you a simple, true fact. The transform function takes two arguments: a function and a list. You're giving it 3 arguments. So something must be wrong.
The transformation you want to happen to each element of the list is a filtering. So, if you remove the + (which really doesn't make any sense) from your transforming function you have something very close to what you want.
Possibly you just need to remove the [] from the arguments of transform. It's not clear (to me) why it's there.