Simpler way to implement map function in OCaml - ocaml

I know List.map uses recursion, I'm just wondering if there's a simpler way to implement map function without using recursion.
I know for reverse, I can simplify it into:
(* given *)
type 'a list =
| []
| (::) of 'a * 'a list
let nil : 'a list = []
let cons (hd : 'a) (tl : 'a list): 'a list = hd :: tl
let reverse (ls : 'a list): 'a list =
List.fold_left (Fun.flip cons) [] ls
Right now I'm thinking about using ##(the application operator), %(the function composition operator), and maybe Fun.flip or List.fold_left to do it, can anyone give me some hint about that?
I have tried the following, but OCaml raised an error about it.
List.fold_left (fun x -> f x) [] ls

List.fold_left uses recursion, so presumably you're looking to avoid use of the rec keyword, rather than recursion at all.
You note in comments trying:
List.fold_left (fun x -> f x) [] ls
But the function passed to List.fold_left must take two arguments: the initial state, and the first element of the list. Fun.flip cons worked in your reverse function because it does take two arguments.
Note: fun x -> f x is the same as writing f.
If you initial state is a list, you need to do something to that list in the function you pass to List.fold_left, like adding the result of f x to the front of it. Since this builds the list backwards, you will need to reverse the result. This is where ## will come in handy.
let map f lst =
List.(
rev ## fold_left (fun i x -> f x :: i) [] lst
)

Related

How to use sml to write a function to turn a list of 2-tuples to a flattened list?

I got a problem that needs to turn a list of tuples into a flattened list for example:
[(1,2), (3,4), (5,6)] can be turned into [1,2,3,4,5,6]
I have tried to write a function like this:
fun helper2(nil,b) = []
| helper2(a,nil) = []
| helper2(a::l1,b::l2) =l1::l2
fun flatten2 [] = []
| flatten2 ((a,b)::tl) = helper2(a,b)
It shows:
val flatten2 = fn : ('a list * 'a list list) list -> 'a list list
And when I tried to run it using command flatten2[(1,2),(3,4),(5,6)];
It will give me the following error message:
stdIn:1.2-1.29 Error: operator and operand do not agree [overload conflict]
operator domain: ('Z list * 'Z list list) list
operand: ([int ty] * [int ty]) list
in expression:
flatten2 ((1,2) :: (3,4) :: (<exp>,<exp>) :: nil)
My questions are:
Why SML see the a and b values as lists, not just simply a and b
How can I revise my code so SML can see a and b as 'a and 'b not lists
How to make this code work the way it should be?
Thanks
First question: As to why the type comes out as ('a list * 'a list list) it's because type inference is looking at this part of the code:
| helper2(a::l1,b::l2) =l1::l2
^^
here
Keep in mind that the type of the "cons" (::) operator is 'a -> 'a list -> 'a list, it is gluing a single element onto a list of that same type of element. So SML has concluded that whatever l1 and l2 are, the relationship is that l2 is a list of whatever l1 is.
fun helper2(nil,b) = []
Says that a must be a list because nil has type 'a list. Therefore, l2 has to be a list of lists (of some type 'a).
Question 2 and 3: I'm not quite sure how to correct the code as it is written. I'd probably write something like this:
fun helper2 [] accum = List.rev accum
| helper2 ((a,b)::tl) accum = helper2 tl (b :: a :: accum);
fun flatten2 list = helper2 list [];
helper2 does all of the dirty work. If the input list is empty then we're all done and we can return the reversed accumulator that we've been building up. The second case is where we actually add things to the accumulator. We pattern match on the head and the tail of the list. This pattern match means that the input has type ('a * 'a) list (a list of tuples where both elements are the same type). In the head, we have a tuple and we name the first and second element a and b, respectively. We prepend a then b onto the accumulator and recursively call helper2 on the tail of the list. Eventually, we'll chew through all the elements in the list and then we'll be left with just the accumulator -- which, recall, has all the elements but in the reverse order. Calling List.rev reverses the accumulator and that's our answer.
And when I load and run it I get this:
- flatten2 [(1,2), (3,4), (5,6)];
val it = [1,2,3,4,5,6] : int list
Why SML see the a and b values as lists, not just simply a and b
Chris already answered this in-depth.
You're passing a as the first argument to helper2, which expects a list as its first argument. And you're passing b as the second argument to helper2, which uses its second argument, b::l2, also a list, as the tail of a list where a is the head. So b must be a list of those lists.
This doesn't make any sense, and is most likely a consequence of confusing syntax: You are passing in what you think of single elements a and b in flatten2, but when you deal with them in helper2 they're now lists where the heads are called a and b. Those are not the same a and b.
How can I revise my code so SML can see a and b as 'a and 'b not lists
You could ditch the helper function to begin with:
fun flatten2 [] = []
| flatten2 ((a,b)::pairs) = a :: b :: flatten2 pairs
The purpose of having a helper function is so that it can accumulate the result during recursion, because this version of flatten2 uses a lot of stack space. It can do this with an extra argument so that flatten2 doesn't need to mention it:
This is the version Chris made.
How to make this code work the way it should be?
You can make this code in a lot of ways. Two ways using explicit recursion were mentioned.
Here are some alternatives using higher-order functions:
(* Equivalent to my first version *)
fun flatten2 pairs =
foldr (fn ((a,b), acc) => a :: b :: acc) [] pairs
(* Equivalent to Chris'es version *)
fun flatten2 pairs =
rev (foldl (fn ((a,b), acc) => b :: a :: acc) [] pairs)
(* Yet another alternative *)
fun concatMap f xs =
List.concat (List.map f xs)
fun flatten2 pairs =
concatMap (fn (a,b) => [a,b]) pairs

Adding values to an ocaml list based on its existing values

I'm learning about the map and fold functions. I'm trying to write a function that takes a list and returns a list with all of the values in the original, each followed by that value's double.
Example: add_dbls [2;5;8] = [2;4;5;10;8;16]
Everything I try results in a list of lists, instead of a list. I'm struggling to come up with a better approach, using either map or fold (or both).
This is what I came up with originally. I understand why this returns a list of lists, but can't figure out how to fix it. Any ideas would be appreciated!
let add_dbls list =
match list with
| h::t -> map (fun a-> [a;(a*2)]) list
| [] -> []
Also, my map function:
let rec map f list =
match list with
| h::t -> (f h)::(map f t)
| [] -> []
You are nearly there. As you have observed, since we get list of lists, we need to flatten it to get a final list. List.concat function does exactly that:
let add_dbls list =
let l =
match list with
| h::t -> List.map (fun a -> [a;(a*2)]) list
| [] -> []
in
List.concat l
Here is the updated function that that computes the output that you require.
Now the output of add_dbls [2;5;8] = [2;4;5;10;8;16].
Although this works, it probably isn't efficient as it allocates a new list per item in your original list. Below are variations of the same function with different characteristics which depend on the size of l.
(* Safe version - no stack overflow exception. Less efficient(time and size) than add_dbls3 below. *)
let add_dbls2 l =
List.fold_left
(fun acc a -> (a*2)::a::acc)
[]
l
|> List.rev
(* Fastest but unsafe - stack overflow exception possible if 'l' is large - fold_right is not tail-recursive. *)
let add_dbls3 l =
List.fold_right
(fun a acc -> a::(a*2)::acc)
l
[]
It's should be simple to see that List.map always returns a list of the same length as the input list. But you want a list that's twice as long. So List.map cannot work for you.
You can solve this using List.fold_left or List.fold_right. If you're still having trouble after you switch to using a fold, you could update your question with the new information.
Update
The type of your fold function (a left fold) is this:
('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
So, the folded function takes an accumulated answer and an element of the list, and it returns a new accumulated answer.
Your folded function is like this:
fun a b -> a::b::(b*2)
It attempts to use the :: operator to add new elements to the end of the accumulated list. But that's not what the :: operator does. It adds an element to the beginning of a list.
There's no particularly nice way to add an element to the end of a list. This is intentional, because it's a slow operation.
When using a left fold, you need to reconcile yourself to building up the result in reverse order and possibly reversing it at the end. Or you can use a right fold (which is generally not tail recursive).

About List.map usage

List.map is of type
- : ('a -> 'b) -> 'a list -> 'b list = <fun>
It's easy for me to understand the following code:
List.map (fun x -> x+1) [1;2;3;4];;
which adds 1 to each element of the list so it returns the following list :
- : int list = [2;3;4;5]
Now this is in an exercise where I'm asked to indicate the type of this :
List.map (fun p -> p 7) [ (fun n m -> n + m) ];;
I don't understand at all what it means to be honest.
What does p 7 mean ?
Why is there a function in the list ?
The type is
- : (int -> int) list = [<fun>]
But I can't understand why.
What does it mean when fun is between brackets ?
Thank you.
What does p 7 mean?
It means the application of function p to argument 7 .... You might spend some time reading the wikipage on λ-calculus (at least to learn about functional abstraction)
Read also about currying.
Why is there a function in the list ?
In Ocaml, functions are values, so you can have list of functions. If it was not a list of functions, you'll get a typing error. If you think more, you can understand what kind of functions are allowed.
What does it mean when fun is between brackets ?
The toplevel is not able to print functional values (implemented as closures). It shows them as <fun>. For a simpler example, pass fun x -> x+1;; (then try also fun y -> y;;) to your REPL.
(the rest of the exercise is left to the reader)

OCaml unexpected type

I have to write a function to remove elements from a lazy list. Indexes of elements to be removed are in list xs.
I don't know where I should sort xs? When I try in this way I get "Error: This expression has type...".
type 'a llist = LNil | LCons of 'a * (unit -> 'a llist)
let rec remove xs ll =
let rec helper =
function
| (_, i, LNil) -> LNil
| (h::t, i, LCons(x, xf)) -> if h = i then helper (t, (i + 1), xf())
else LCons(x, fun() -> helper (h::t, (i + 1), xf()))
| ([], i, LCons(x, xf)) -> LCons(x, xf)
in helper (List.sort xs, 0, ll);;
List.sort from OCaml standard library has the following interface:
val sort : ('a -> 'a -> int) -> 'a list -> 'a list
That means, that it accepts a function and a list. The function should have type 'a -> 'a -> int, i.e., it takes two elements of arbitrary type 'a and returns a value of type int that defines the mutual order of the arguments. The second argument is a list of values, where each value has type 'a. A usual invocation of the sort function is:
List.sort compare [2;1;4;3]
So with this knowledge we can tackle with your program:
You invoke List.sort on xs this has two consequences:
type inference system concludes that xs is a function of type 'a -> 'a -> int.
The result of List.sort xs is a function of type 'a list -> 'a list. This is because, List.sort requires two arguments, but you provided only one.
(List.sort xs) is a function that takes a list & returns a list - as xs is supposed to be the function that sorts the element of the list; you miss to pass a list as arg.
...whereas a list is expected.

Ocaml evaluate boolean list to single boolean

when trying to write a simple program for solving a toy SAT problem, I came across the following problem I cannot get my head around.
I have a type variable which is defined as follows:
type prefix =
| Not
| None
type variable =
| Fixed of (prefix * bool)
| Free of (prefix * string)
from which I can build a clause of type variable list and a formula of type clause list. Essentially this boils down to having a formula in
either CNF or DNF (this has less to do with the problem).
When now trying to simplify a clause I do the following:
Filter all Fixed variables from the clause which gives a list
Simplify the variables (Fixed(Not, true) => Fixed(None, false))
Now I have a list containing just Fixed variables which I now want to combine to a single Fixed value by doing something like this
let combine l =
match l with
| [] -> []
| [x] -> [x]
| (* Get the first two variables, OR/AND them
and recurse on the rest of the list *)
How would I achieve my desired behavior in a functional language? My experience in OCaml is not that big, I am rather a beginner.
I tried doing x::xs::rest -> x <||> xs <||> combine rest but this does not work. Where <||> is just a custom operator to OR the variables.
Thanks for your help.
How about using the neat higher order functions already there?
let combine = function
| x::xs -> List.fold_left (<||>) x xs
| [] -> failwith "darn, what do I do if the list is empty?"
For clarification:
List.fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
takes a function that gets the running aggregate and the next element of the list; it returns the new aggregate; then we need an initial value and the list of items to fold over.
The use of your infix operator <||> in brackets makes it a prefix function so we can give it to List.fold_left just like that -- instead of writing (fun a b -> a <||> b).
If you have a neutral element of your <||> operator, lets call it one, we could write it even more concise:
let combine = List.fold_left (<||>) one
As List.fold_left requires three arguments and we only gave it two, combine here is a function of variable list -> variable as the previous one. If you wonder why this works, check out the concept of currying.
Here's my attempt:
let rec combine l =
match l with
| [] -> []
| [x] -> [x]
| a :: b :: rest -> combine ((a <||> b) :: rest)
Note you need let rec.