I'm new to OCaml and attempting to implement List.append as a learning exercise. This is what I have:
let rec append a b =
match (List.rev a) with
[] -> b
| x:: xs -> append xs (x::b)
This seems to work until argument a has more than two elements. Example:
# append [1;2] [3;4]
- : int list = [1; 2; 3; 4]
# append [1;2;3] [4;5;6]
- : int list = [2; 1; 3; 4; 5; 6]
What's going on here? I've checked, and List.rev [1;2;3] returns int list = [3; 2; 1]. I know my implementation is naïve and not (yet) lazy, but it seems like it should work.
If you think about it, you are reversing your first list quite a few times. Probably more than you wanted to.
You can see what's happening if you follow the steps of an example.
append [1; 2; 3] []
(* match binds x to 3, xs to [2; 1] *)
append [2; 1] [3]
(* match binds x to 1, xs to [2] *)
append [2] [1; 3]
(* match binds x to 2, xs to [] *)
append [] [2; 1; 3]
(* done *)
Related
I tried to write my own solution for this exercise by iterating through a list with a empty complst list where all non duplicates are inserted into and then get returned.
I know it is a over complicated approach after looking up the solution but would still like to understand why the pattern matching does not work as intended:
let compress list =
let rec aux complst lst =
match lst with
| [] -> complst
| a :: (b :: c) -> if a = b then aux complst (b::c) else aux (a::complst) (b::c)
| x -> x
in aux [] list;;
val comp : 'a list -> 'a list = <fun>
Regardless of the input, the output is always a list with only the last element:
compress [1;1;2;2;3];;
- : int list = [3]
compress [1;2;3];;
- : int list = [3]
Pattern matching
Your pattern-matching matches against three patterns:
The empty list: []
The list with at least two elements: a :: (b :: c)
A catch-all, which must by process of elimination be a list with a single element.
Consider what happens when we evaluate your example:
compress [1; 1; 2; 2; 3]
aux [] [1; 1; 2; 2; 3]
aux [] [1; 2; 2; 3]
aux [1] [2; 2; 3]
aux [1] [2; 3]
aux [2; 1] [3]
[3]
Oops, as soon as it hit lst being [3] it just returned it.
Let's rewrite your function to handle that single element list by adding to complst.
let compress lst =
let rec aux complst lst =
match lst with
| [] -> complst
| [x] -> aux (x::complst) []
| a :: (b :: c) ->
if a = b then aux complst (b::c)
else aux (a::complst) (b::c)
in
aux [] list
Now:
compress [1; 1; 2; 2; 3]
aux [] [1; 1; 2; 2; 3]
aux [] [1; 2; 2; 3]
aux [1] [2; 2; 3]
aux [1] [2; 3]
aux [2; 1] [3]
aux [3; 2; 1] []
[3; 2; 1]
Clean up and reversing the resulting list
Of course, there are also ways to clean up your code a bit using a conditional guard and _ for values you don't need to bind names to. You probably also want to reverse your accumulator.
let compress lst =
let rec aux complst lst =
match lst with
| [] -> List.rev complst
| [x] -> aux (x::complst) []
| a :: (b :: _ as tl) when a = b -> aux complst tl
| a :: (_ :: _ as tl) -> aux (a::complst) tl
in
aux [] lst
Fold
When you see this pattern of iterating over a list one element at a time and accumulating a new value, you can usually map that pretty well to List.fold_left.
let compress lst =
List.(
fold_left
(fun i x ->
match i with
| (x'::_) when x = x' -> i
| _ -> x::i)
[] lst
|> rev
)
Because List.fold_left can only be aware of one element at a time on the list, the function we pass as its first argument can't be aware of the next element in the list. But it is aware of the accumulator or "init" value. In this case that's another list, and we can pattern match out that list.
If it's not empty and the first element is equal to the current element we're looking at, don't add it to the result list. Otherwise, do add it. This also handles the first element case where the accumulator is empty.
Kudos on creating a tail-recursive solution to this problem!
The problem with your code here is mainly the last part, which corresponds to when you have the last element in your list so here [3], and you return that list with this single element.
What you need to do instead is append it to complst like this :
let compress list =
let rec aux complst lst =
match lst with
| [] -> complst
| a :: (b :: c ) -> if a=b then aux complst (b::c) else aux (a::complst) (b::c)
| x::e -> x::complst
in aux [] list;;
val comp : 'a list -> 'a list = <fun>
Now you can check with the given example :
compress [1;1;2;2;3];;
- : int list = [3; 2; 1]
Hope it helps you understand your mistake better.
Note regarding comments:
you should keep the [] case, because although it can only happen in one scenario, it is still a valid input meaning it must be kept!.
I have a question regarding the execution flow in recursive functions in OCaml. This is scenario:
I have two recursive functions, Concat and Reverse. Reverse calls Concat. Would anyone be able to explain what happens when I, for example, submits the list [1; 2; 3]?
let rec concat (l1,l2) =
match l1 with
[] -> l2
| (h::t) -> h::(concat (t,l2));;
let rec reverse (l: int list) =
match l with
[] -> []
| (h :: t) -> concat (reverse t, [h]);;
// Call
let list1 = [1; 2; 3] ;;
reverse list1 ;;
I know this is not the optimal way to reverse a list, but right now I only interested in how two recursive functions work with each other.
Thanks!
If you annotate concat as taking two lists of ints:
let rec concat (l1, l2 : int list * int list) =
. . .
You can ask the toplevel (OCaml REPL) to trace the function calls and return values. This might tell you exactly what you want to know.
$ rlwrap ocaml
OCaml version 4.06.1
. . .
# trace concat;;
concat is now traced.
# trace reverse;;
reverse is now traced.
# reverse [1; 2; 3];;
reverse <-- [1; 2; 3]
reverse <-- [2; 3]
reverse <-- [3]
reverse <-- []
reverse --> []
concat <-- ([], [3])
concat --> [3]
reverse --> [3]
concat <-- ([3], [2])
concat <-- ([], [2])
concat --> [2]
concat --> [3; 2]
reverse --> [3; 2]
concat <-- ([3; 2], [1])
concat <-- ([2], [1])
concat <-- ([], [1])
concat --> [1]
concat --> [2; 1]
concat --> [3; 2; 1]
reverse --> [3; 2; 1]
- : int list = [3; 2; 1]
Functions, recursive or not, are evaluated by first evaluating all it's arguments in an unspecified order and then calling the function with them.
So for example concat (reverse t, [h]) will first evaluate reverse and then call concat.
I have a function:
let rec multiply x ls =
match ls with
[] -> []
| h::tl -> (x * h) :: multiply x tl
multiply 2 [1;2;3] = [2;4;6]
I would like a function that calls multiply from n to 0. I keep having problems because of the base case:
let rec multiply_all x ls = if x > 0
then (multiply n ls) :: multiply_all (n-1) (ls) else ????
I am not sure what to put after the else. I tried to make it
if x > 1 then (multiply n ls) :: multiply_all (n-1) (ls) else multiply all 1.
but that doesn't work.
Putting 1 there certainly doesn't work since multiply_all must return a list. So you need a list (of lists of int) to put there. But which list should it be?
The short answer is that in such simple cases, the list you need is usually the empty list: [].
As a slightly longer answer, we can consider the case for multiply_all 0 in relation to the intended results of multiply_all 1, multiply_all 2, etc., and try to find a pattern that fits. We want multiply_all to behave like this:
# multiply_all 2 [1;2;3];;
- : int list list = [[2; 4; 6]; [1; 2; 3]]
# multiply_all 1 [1;2;3];;
- : int list list = [[1; 2; 3]]
So calling multiply_all with some number N as first argument should give us a list of length N. In particular, multiply_all with N = 0 should give a list of length 0. The list of length 0 is the empty list.
Here is your completed definition:
let rec multiply_all x ls =
if x > 0 then (multiply x ls) :: multiply_all (x-1) (ls) else []
Just an other solution :
let multiply_all n l =
let multiply n= List.map (( * ) n) in
let rec aux i acc =
if i > n then acc
else aux (i+1) (multiply i l :: acc)
in
aux 1 []
;;
Test :
# multiply_all 5 [1;2;3];;
- : int list list =
[[5; 10; 15]; [4; 8; 12]; [3; 6; 9]; [2; 4; 6]; [1; 2; 3]]
First of all, your multiply method is pretty inefficient since it isn't tail recursive. Furthermore, the standard library provides you with tools to make that kind of function easier to write:
let multiply n = List.map (( * ) n);;;
val multiply : int -> int list -> int list = <fun>
multiply 5 [1;2;3];;
- : int list = [5; 10; 15]
Note: Also, use partial application when it doesn't obfuscate your code.
As of multiply_all, I'm not sure how to achieve it without JaneStreet's Core (see this question). However, here is a possible implementation using Core:
open Core.Std;; (*Using Core*)
let multiply_all n l =
let multiples = List.init n ~f:(fun x -> n-x) in (*This doesn't exist in Pervasives*)
List.map multiples ~f:(fun m -> multiply l m);;
val multiply_all : int list -> int -> int list list = <fun>
multiply_all 5 [1;2;3];;
- : int list list = [[5; 10; 15]; [4; 8; 12]; [3; 6; 9]; [2; 4; 6]; [1; 2; 3]]
Hope it helps. I'll keep this answer updated with my findings about List.init.
How can I add an element into a int list list?
|x::y::xs-> if(x<=y)
then [x]#(ordina (y::xs))
else [x]::ordina (y::xs)
I tried with this, but it didn't work..
To add a new int list containing x to the head of an int list list:
# let x = 14 in
let ill = [[3;4]; [5;6]] in
[x] :: ill ;;
- : int list list = [[14]; [3; 4]; [5; 6]]
You can also write this:
# let x = 14 in
let ill = [[3;4]; [5;6]] in
[[x]] # ill ;;
- : int list list = [[14]; [3; 4]; [5; 6]]
But this entails a tiny amount of unnecessary work.
As a side comment, the two branches of your if look like they're trying to do the same thing. If you want the result to be [[14; 3; 4]; [5; 6]] you need to write a little more code to destructure the int list list.
# let x = 14 in
let ill = [[3;4]; [5;6]] in
match ill with
| [] -> [[x]]
| h :: t -> (x :: h) :: t ;;
- : int list list = [[14; 3; 4]; [5; 6]]
How to get sublists
[1]; [1; 2]; [1; 2; 3]; ...; [1; 2; 3; ...; n]
from list
[1; 2; 3; ...; n]
by the most idiomatic way? All that I could is:
List.scan (fun acc elem -> elem::acc) [] [1;2;3;4;5]
> val it : int list list =
[[]; [1]; [2; 1]; [3; 2; 1]; [4; 3; 2; 1]; [5; 4; 3; 2; 1]]
Thanks.
Your implementation is fine. Here is my alternative:
let source = [1..10]
let counts = [0..source.Length] // Or start at 1 if you don't want to start with an empty list
counts |> List.map (fun count -> source |> List.take count)
Throwing mine onto the pile, which is maybe a refinement of Foole's answer:
let inits list =
list |> List.mapi (fun i _ -> List.take (i + 1) list)
mapi is a useful function: You provide it a function which takes the each index and item.
Here's another one:
let f n = List.init n (fun i -> [1..(i + 1)])
List.init exists for the task of initializing a list.