I want to write a function that gives the cartesiant product of two sequences that's what i did but i thought that it can be interesting to have less complexity with I want to browsing once the first sequence s1 and n times the second using map and then append all the results:
`let cartesian_product a b =
let na = length a in
let nb = length b in
init
(na * nb)
(fun j -> let i = j / nb in
at a i, at b (j - i*nb))
`
that's what i did for the moment :
`let rec cartesian_product a b =
let rec aux x b () = match b () with
| Nil -> Nil
| Cons(e, b) -> Cons ((x, e), aux x b)
in
match a () with
| Nil -> nil
| Cons (x, a) -> append (aux x b) (cartesian_product a b)`
but i didn't use map (is there a better way for doing that)??
Your aux function is essentially a specific case of map so you can write:
let rec cartesian_product a b = match a () with
| Nil -> Nil
| Cons (x, a) -> append (map (fun e -> (x, e)) b) (cartesian_product a b)
As a rule of thumb when you feel the need to write a function called aux, take a step back and think whether you can use map or fold. In fact, you could improve my code by using a fold instead of deconstructing the sequence yourself.
Here an example of the algorithm with a structure of list :
let cartesian_product a b =
let open List in
let mk_tuple l n = map (fun x -> (n,x)) l in
a |> map (mk_tuple b) |> fold_left append []
This will give you :
cartesian_product [0;1] [2;3];;
- : (int * int) list = [(0, 2); (0, 3); (1, 2); (1, 3)]
Related
How to create a tuple list from one single list, like so:
[1; 2; 4; 6] -> [(1, 2); (4, 6)]
I want to do it using function List.fold_left since I'm trying to learn that currently but don't know how... Is there a way? Or should I leave it like that?
This is a working code that doesn't use List.fold_left:
let rec create_tuple acc l = match l with
| [] -> acc
| x :: y :: l' -> create_tuple (acc # [(x, y)]) l'
| _ -> acc
List.fold_left reads elements one by one. There is no direct way to make it read elements two by two.
It really is pointless complication (great for teaching, though), but if you absolutely want to use List.fold_left here, your accumulator needs to somehow record the state of the traversal:
either you have read an even number of elements so far,
or you have read an odd number and then you have to record what was the last element you read, so that, upon reading the following one, you can pair them.
Here is a way to do it. I use an algebraic datatype to represent the state.
(* This is the type that we’ll use for the accumulator;
the option component is the state of the traversal.
(None, acc) means that we have read an even number of elements so far;
(Some x, acc) means that we have read an odd number of elements so far,
the last of which being x. *)
type 'a accumulator = 'a option * ('a * 'a) list
let folder (state, acc) x =
match state with
| None -> (Some x, acc)
| Some y -> (None, (y,x)::acc)
let create_pairs l =
let (_, acc) = List.fold_left folder (None, []) l in
List.rev acc
Also notice how I avoid the complexity bug that I outlined in a comment: I add elements in reverse order (i.e. at the head of the accumulating list), and at the very end I reverse that list.
#Maëlan's answer is beautiful, but what if we want to get triples rather than pairs? Is there a way we can use List.fold_left to handle this more generically?
let chunks n lst =
let (_, _, acc) = List.fold_left
(fun (counter, chunk, lst') x ->
if counter = n - 1 then
(0, [], List.rev (x :: chunk) :: lst')
else
(counter + 1, x :: chunk, lst'))
(0, [], [])
lst
in
List.rev acc
Using this, chunks 2 [1; 2; 4; 6] returns [[1; 2]; [4; 6]]. We can map this to the result you're looking for with a very simple function that takes a list with two elements and creates a tuple with two elements.
chunks 2 [1; 2; 4; 6] |> List.map (fun [x; y] -> (x, y))
And we get:
[(1, 2), (4, 6)]
This could be used to implement a triples function.
let create_triples lst =
chunks 3 lst |> List.map (fun [x; y; z] -> (x, y, z));;
And now create_triples [1; 2; 3; 4; 5; 6; 7; 8; 9] returns [(1, 2, 3); (4, 5, 6); (7, 8, 9)].
I tried this question(using List.fold_left) and this is the best I could come up with:
type 'a node = First of 'a | Second of ('a * 'a)
let ans =
List.fold_left
(
fun a e ->
match a with
| [] -> (First e)::a
| (First f)::tl -> Second(f, e)::tl
| (Second n)::tl -> (First e)::(Second n)::tl
)
[]
[1; 2; 3; 4; 5; 6; ]
let () =
List.iter
(
fun e ->
match e with
| First f ->
print_endline(string_of_int f)
| Second (f, s) ->
Printf.printf "(%d, %d)" f s
)
(List.rev ans)
Just to make my answer all there...
type 'a node = One of 'a | Two of ('a * 'a)
let ans =
(List.map
(
fun e ->
match e with
| One _ -> failwith "Should only be Two's"
| Two (f, s) -> (f, s)
)
(List.filter
(
fun e ->
match e with
| One _ -> false
| Two _ -> true
)
(List.rev
(List.fold_left
(
fun a e ->
match a with
| [] -> (One e)::[]
| (One o)::tl -> (Two (o, e))::tl
| (Two t)::tl -> (One e)::(Two t)::tl
)
[]
(List.init 10 (fun x -> x + 1))
)
)
)
)
let () =
List.iter
(fun (f, s) -> Printf.printf "(%d, %d) " f s)
ans
I’m trying to create a function that takes an int list as an argument and returns the sum of the product between an int and its position in the list. To put in an example this : multSum [5; 11; 15] should return (5 * 1 + 11 * 2 + 15 * 3) = 72.
It should be written recursively and I’m trying while avoiding List.map or List.filter or any other prefabricated functions.
By dividing and reigning the query above, I have so far started by trying the following :
let rec tir f acc l =
match l with
|[] -> acc
|h::t -> tir f (f acc h) t ;;
val tir : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>
then I moved to this :
let rec carto f a b =
match (a,b) with
|([],[])->([])
|(h1::t1,h2::t2)->(f h1 h2):: (carto f t1 t2)
|_->invalid_arg "carto";;
val carto : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list = <fun>
with the final idea to be able to do that :
let prod arg1 arg2 =
tir (+) 1 (carto ( * ) arg1 arg2);;
val prod : int list -> int list -> int = <fun>
But I am stuck now and I’m not sure of my orientation from here forward. I thought of trying to search for the index in a "l" and replace each index int in the acc, in order to make it work but I'm afraid I'm rather complicating things... Any help please ?
Edit 1 :
let rec multSum l =
let rec indices n xs = match xs with
| [] -> []
| h::t -> n::(indices (n+1) t)in
let rec tir f acc l =
match l with
|[] -> acc
|h::t -> tir f (f acc h) t in
let rec carto f a b =
match (a,b) with
|([],[])->([])
|(h1::t1,h2::t2)->(f h1 h2):: (carto f t1 t2)
|_->invalid_arg "carto" in
let prod arg1 arg2 =
tir (+) 0 (carto ( * ) arg1 arg2) in
prod l (indices 1 l);;
val multSum : int list -> int = <fun>
Building on your replies, surely these are 'fold' and 'map' rewritten. At least, I'm sure now that I was on the right track. I have come to put together the whole code as signaled above in Edit 1.
It seems to be working well... I know that I want a recursive function and here it is. But, do you think it could be done even shorter recursively of course?
#coredump is quite right about this looking like an ideal scenario for a fold, but the extra functions aren't really that necessary. We can just use a tuple to pass the index and sum information around, then when we're done, discard the index information from the tuple.
let sum_list_prod lst =
let (_, result) = List.fold_left
(fun (i, sum) x -> (i + 1, sum + i * x))
(1, 0)
lst
in
result
Edit: A simple implementation of a left fold to demonstrate the recursion going on here.
let rec foldl f init lst =
match lst with
| [] -> init
| first :: rest -> foldl f (f init first) rest
So working through a simple example with sum_list_prod:
sum_list_prod [2; 3; 4]
Calls the fold like so:
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (1, 0) [2; 3; 4]
And as that evaluates:
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (1, 0) [2; 3; 4]
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (2, 2) [3; 4]
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (3, 8) [4]
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (4, 20) []
(4, 20)
And then we throw away the 4 because we don't need it anymore and are just left with 20.
Your tir functions looks like a fold; in fact has the exact same type as List.fold_left:
# List.fold_left;;
- : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>
In the following snippets the prod function looks like a map2
# List.map2;;
- : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list = <fun>
You can use a fold and a map to compute the function you want, but you also need first to build a list of indices from the list of values. You could do this as follows:
let rec indices n xs = match xs with
| [] -> []
| h::t -> n::(indices (n+1) t);;
For example:
# indices 1 [5;1;3];;
- : int list = [1; 2; 3]
This is not recursive terminal, if you first computed the length of the list, how would you build the list in a recursive terminal way?
Then you should be able to call prod on a list xs and on a secondary list indices 1 xs. It is a bit wasteful because you need to build an auxiliary list, but it looks quite simple to me to understand, higher-order functions like map or fold do work on whole lists so there are fewer corner cases to consider.
But, it might be better to first write a direct recursive function for your particular problem before going the more abstract route.
The direct recursive function also requires no additional memory allocation. If you write a recursive terminal function you'll carry additional accumulator values:
the current position in the list, initially 1
the current sum of products, initially 0
Then, your function has the following skeleton:
let rec f xs index product = match xs with
| [] -> ...
| h::t -> ...
You can wrap it in a main function g:
let g xs = f xs 1 0;;
I have a list of (string * int) list elements and I need to find the biggest int element and return the corresponding(string * int) element.
I have something like this atm, but problem is, I think my approach is more of "typical programming"
let it = [] in
for x = 0 to length LIST - 1 do
let str = ((List.nth LIST x).string) in
let num = ((List.nth LIST x).int) in
let it = it # [num, str] in
let (str, num) = List.hd(List.rev it) in
[str, num]
What I tried to do is to loop through the list and add the string and int value in another list, then sort them, reverse it and then take the head, which should be the max int, then I need to return the pair in (string * int)
Your code is not a well-formed OCaml code. It highlights, however, some number of issues with your understanding of OCaml.
First of all, by default, values in OCaml are immutable. For example,
let x = 0 in
for i = 0 to 10 do
let x = x + 1 in
print_int x;
done
You will get 11111111111 as the output. This is because, during the loop, you are just computing every time the x+1 expression, where x is always 0 and you will always get 1 as the result. This is because, let x = <expr> in <body> is not changing the existing variable x but is creating a new variable x (shadowing any previous definitions) and make it available in the scope of the <body> expression.
Concerning your problem in general, it should be solved as a recursive function greatest_element, which has the following definition,
for an empty list [] it is undefined;
for a list of one element [x] is it is x;
otherwise, for a list of x::xs it is max x (greatest_element xs),
where max x y is x if it is greater or equal to y.
Finally, it looks like you have missed the first steps in OCaml and before solving this task you have to move back and to learn the basics. In particular, you have to learn how to call functions, bind variables, and in general what are the lexical conventions and syntax of the language. If you need pointers, feel free to ask.
First of all, it doesn't seem that you did any kind of sorting in
the code that you provided.
Assuming that your list is of type
(string * int) list then a possible to find the element with the
maximum integer using recursion:
let max_in_list list =
let rec auxiliary max_str max_int = function
| []
-> (max_str, max_int)
| (crt_str, crt_int)::tail when crt_int > max_int
-> auxiliary crt_str crt_int tail
| _::tail
-> auxiliary max_str max_int tail
in
match list with
| []
-> None
| (fst_str, fst_int)::tail
-> Some (auxiliary fst_str fst_int tail)
let check = max_in_list [("some", 1); ("string", 3); ("values", 2)]
You could write a generic maxBy function. This allows you to get the max of any list -
let rec maxBy f = function
| [] -> None
| [ x ] -> Some x
| x :: xs ->
match (maxBy f xs) with
| Some y when (f y) > (f x) -> Some y
| _ -> Some x
(* val maxBy : ('a -> 'b) -> 'a list -> 'a option = <fun> *)
let data = [("a", 3); ("b", 2); ("c", 6); ("d", 1)]
(* val data : (string * int) list = [("a", 3); ("b", 2); ("c", 6); ("d", 1)]*)
maxBy (fun (_, num) -> num) data
(* - : (string * int) option = Some ("c", 6) *)
maxBy (fun (str, _) -> str) data
(* - : (string * int) option = Some ("d", 1) *)
maxBy (fun x -> x) [3; 2; 6; 1]
(* - : int option = Some 6 *)
maxBy (fun x -> x) ["c"; "d"; "b"; "a"]
(* - : string option = Some "d" *)
maxBy (fun x -> x) []
(* - : 'a option = None *)
It can be fun to rewrite the same function in various ways. Here's another encoding -
let maxBy f list =
let rec loop r = function
| [] -> r
| x::xs when (f x) > (f r) -> loop x xs
| _::xs -> loop r xs
in
match list with
| [] -> None
| x::xs -> Some (loop x xs)
(* val maxBy : ('a -> 'b) -> 'a list -> 'a option = <fun> *)
I have a homework practice problem and I am new to F# and the syntax is so confusing, I do not know where to start
For example, If I have a list of tuples of increasing values :
let tupleList = [(1,2,3);(10,12,15);(9,10,20)]
I should write a function that returns a tuple that has the largest middle value.
So the function should return :
(10,12,15)
Any hints on what should I consider, read on the Internet, or research, or any other tips to help me learn how to do this is appreciated!
Thank you!
You should probably read a book on F# or work through https://fsharpforfunandprofit.com/
You can use List.max or List.maxBy to get the maximum in a list. Because you have a three element tuple, you will need to deconstruct it (as there is no function to access the nth element of a tuple, only the first or the second one). Once you exposed the middle value you can run maxby on it, and get rid of the unnecessary parts.
let tupleList = [(1,2,3);(10,12,15);(9,10,20)]
tupleList
|> List.map (fun (a,b,c) -> (b, (a,b,c)))
|> List.maxBy fst
|> snd
val it : int * int * int = (10, 12, 15)
If none of built-in function can be used, then you can use either (1) mutable variables and while loop or (2) recursion.
Since you are learning functional programming, it is very likely that your professor will prefer recursion. Here is the solution:
let max2 (a,b,c) (x,y,z) = if b > y then (a,b,c) else (x,y,z)
let maxMany tuples =
let rec loop currentMaxTuple remainTuples =
match remainTuples with
| [] -> currentMaxTuple
| tuple :: rest ->
let newMaxTuple = max2 currentMaxTuple tuple
loop newMaxTuple rest
match tuples with
| [] -> None
| head :: rest -> Some (loop head rest)
let tupleList = [(1,2,3);(10,12,15);(9,10,20)]
maxMany tupleList |> printfn "%A"
Slightly different from #Nghia Bui's solution, you can use pattern matching to compare tuples items.
let maxSnd tuples =
let rec loop list tuple =
match list, tuple with
| [], _ -> tuple
| (x, y, z) :: xs, (a, b, c) ->
if y < b then (a, b, c) else (x, y, z)
|> loop xs
match tuples with
| [] -> invalidArg "tuples" "Empty list"; 0, 0, 0
| x :: xs -> loop xs x
A little late but anyway:
let maxByMiddle data =
let rec find lst =
match lst with
| [] -> Error("No entries in list")
| [a, b, c] -> Ok(a, b, c)
| (_, bmax, _)::(a, b, c)::tail when b > bmax -> find ((a, b, c)::tail)
| maxima::_::tail -> find (maxima::tail)
find data
fold_right gives me values starting from the tail of the list but I want to give a function to fold_right as a parameter such that this function would collect values starting from the head of the list .
I want iterto receive values starting with the head of the list.
Continous Passing is the keyword ... .Another way to ask the question would be how tofold_leftwith fold_right
let fold f ls acc = List.fold_right f ls acc
val iter : ('a -> unit) -> 'a t -> unit
let iter f my_type =
let rec iiter my_type return =
return (fold (fun x y -> f x) my_type ()) () in iiter my_type (fun x y -> ())
But when I call :
iter (fun a -> print_string a) ["hi";"how";"are";"you"];;
Output:
youarehowhi
I need
hihowareyou
This is quite simple, you must try to match the signatures for the behavior.
Iteration takes no input, and returns unit, while folding takes an input and returns an output of the same type. Now, if the input taken by folding is unit then you'll have a folding function which applies a function on each element of a collection by passing an additional unit and returning an unit, which basically corresponds to the normal iteration, eg:
# let foo = [1;2;3;4;5];;
# List.fold_left (fun _ a -> print_int a; ()) () foo;;
12345- : unit = ()
As you can see the fold function just ignores the first argument, and always returns unit.
let fold_left f init ls =
let res = List.fold_right (fun a b acc -> b (f acc a)) ls (fun a -> a)
in res init
now calling
fold_left (fun a b -> Printf.printf "%s\n" b) () ["how";"are";"you"];;
gives us
how
are
you
fold_left is like List.fold_left but constructed with List.fold_right (Not tail-recursive):
let fold_left f a l = List.fold_right (fun b a -> f a b) (List.rev l) a ;;
Is not a good idea, because fold_left is not tail-recursive and List.fold_left is tail-recursive. Is better to produce a fold_right (tail-recursive) as :
let fold_right f l a = List.fold_left (fun a b -> f b a) a (List.rev l) ;;
If you can't use List.rev :
let rev l =
let rec aux acc = function
| [] -> acc
| a::tl -> aux (a::acc) tl
in
aux [] l
;;
iter use fold_left :
let iter f op = ignore (fold_left (fun a b -> f b;a) [] op ) ;;
Test :
# fold_left (fun a b -> (int_of_string b)::a ) [] ["1";"3"];;
- : int list = [3; 1]
# rev [1;2;3];;
- : int list = [3; 2; 1]
# iter print_string ["hi";"how";"are";"you"];;
hihowareyou- : unit = ()
The continuation that you need to pass through fold in this case is a function that will, once called, iterate through the rest of the list.
EDIT: like so:
let iter f list = fold
(fun head iter_tail -> (fun () -> f head;; iter_tail ()))
list
()