204 lines
4.1 KiB
Org Mode
204 lines
4.1 KiB
Org Mode
#+TITLE: 99 Ocaml Problems
|
|
#+Author: Joseph Ferano
|
|
|
|
https://ocaml.org/problems
|
|
|
|
*** #1 Tail of a list
|
|
|
|
Write a function ~last : 'a list -> 'a option~ that returns the last element of a
|
|
list
|
|
|
|
#+begin_src ocaml
|
|
# last ["a" ; "b" ; "c" ; "d"];;
|
|
- : string option = Some "d"
|
|
# last [];;
|
|
- : 'a option = None
|
|
#+end_src
|
|
|
|
**** Solution
|
|
#+begin_src ocaml
|
|
let rec last = function
|
|
| [] -> None
|
|
| [x] -> Some x
|
|
| _::xs -> last xs
|
|
#+end_src
|
|
|
|
*** #2 Last two elements of a list
|
|
|
|
Find the last but one (last and penultimate) elements of a list.
|
|
|
|
#+begin_src ocaml
|
|
# last_two ["a"; "b"; "c"; "d"];;
|
|
- : (string * string) option = Some ("c", "d")
|
|
# last_two ["a"];;
|
|
- : (string * string) option = None
|
|
#+end_src
|
|
|
|
**** Solution
|
|
#+begin_src ocaml
|
|
let rec last_two = function
|
|
| [] | [_] -> None
|
|
| [x;y] -> Some (x,y)
|
|
| _::xs -> last_two xs
|
|
#+end_src
|
|
|
|
*** #3 N'th element of a list
|
|
|
|
Find the N'th element of a list.
|
|
|
|
REMARK: OCaml has List.nth which numbers elements from 0 and raises an exception
|
|
if the index is out of bounds.
|
|
|
|
#+begin_src ocaml
|
|
# List.nth ["a"; "b"; "c"; "d"; "e"] 2;;
|
|
- : string = "c"
|
|
# List.nth ["a"] 2;;
|
|
Exception: Failure "nth".
|
|
#+end_src
|
|
|
|
**** Solution
|
|
#+begin_src ocaml
|
|
let rec nth index = function
|
|
| [] -> failwith "nth"
|
|
| x::xs -> if index = 0 then x else nth (index - 1) xs
|
|
#+end_src
|
|
|
|
*** #4 Find the number of elements of a list.
|
|
|
|
OCaml standard library has List.length but we ask that you reimplement it. Bonus for a tail
|
|
recursive solution.
|
|
|
|
#+begin_src ocaml
|
|
# length ["a"; "b"; "c"];;
|
|
- : int = 3
|
|
# length [];;
|
|
- : int = 0
|
|
#+end_src
|
|
|
|
**** Solution
|
|
#+begin_src ocaml
|
|
let length list =
|
|
let rec length_rec acc = function
|
|
| [] -> acc
|
|
| _::xs -> length_rec (acc + 1) xs
|
|
in length_rec 0 list
|
|
#+end_src
|
|
|
|
*** #5 Reverse a list.
|
|
|
|
OCaml standard library has List.rev but we ask that you reimplement it.
|
|
|
|
#+begin_src ocaml
|
|
# rev ["a"; "b"; "c"];;
|
|
- : string list = ["c"; "b"; "a"]
|
|
#+end_src
|
|
|
|
**** Solution
|
|
#+begin_src ocaml
|
|
let rev (list: int list) =
|
|
let rec rev acc = function
|
|
| [] -> acc
|
|
| x::xs -> rev (x::acc) xs
|
|
in rev [] list
|
|
#+end_src
|
|
|
|
|
|
*** #6 Palindrome
|
|
|
|
Find out whether a list is a palindrome.
|
|
|
|
HINT: a palindrome is its own reverse.
|
|
|
|
#+begin_src ocaml
|
|
# is_palindrome ["x"; "a"; "m"; "a"; "x"];;
|
|
- : bool = true
|
|
# not (is_palindrome ["a"; "b"]);;
|
|
- : bool = true
|
|
#+end_src
|
|
|
|
**** Solution
|
|
#+begin_src ocaml
|
|
let is_palindrome list = list = List.rev list
|
|
#+end_src
|
|
|
|
|
|
*** #7 Flatten a list
|
|
|
|
Flatten a nested list structure.
|
|
|
|
#+begin_src ocaml
|
|
type 'a node =
|
|
| One of 'a
|
|
| Many of 'a node list
|
|
|
|
# flatten [One "a"; Many [One "b"; Many [One "c" ;One "d"]; One "e"]];;
|
|
- : string list = ["a"; "b"; "c"; "d"; "e"]
|
|
#+end_src
|
|
|
|
**** Solution
|
|
#+begin_src ocaml
|
|
let flatten nodes =
|
|
let rec f = function
|
|
| One x -> [x]
|
|
| Many xs -> List.concat_map f xs
|
|
in nodes |> List.concat_map f
|
|
|
|
(* Or without List.concat_map *)
|
|
|
|
let flatten2 nodes =
|
|
let rec f acc = function
|
|
| [] -> acc
|
|
| One n::ns -> f (n::acc) ns
|
|
| Many ns::rest -> f (f acc ns) rest
|
|
in f [] nodes |> List.rev
|
|
#+end_src
|
|
|
|
|
|
*** #8 Eliminate duplicates
|
|
|
|
Eliminate consecutive duplicates of list elements.
|
|
|
|
#+begin_src ocaml
|
|
# compress ["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "e"; "e"; "e"; "e"];;
|
|
- : string list = ["a"; "b"; "c"; "a"; "d"; "e"]
|
|
#+end_src
|
|
|
|
**** Solution
|
|
#+begin_src ocaml
|
|
let compress list =
|
|
let rec f acc list =
|
|
match (list, acc) with
|
|
| [] , _ -> acc
|
|
| x::xs , y::_ when x = y -> f acc xs
|
|
| x::xs , _ -> f (x::acc) xs
|
|
in f [] list |> List.rev
|
|
#+end_src
|
|
|
|
|
|
|
|
*** #9 Pack consecutive duplicates
|
|
|
|
Pack consecutive duplicates of list elements into sublists.
|
|
|
|
#+begin_src ocaml
|
|
# pack ["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "d"; "e"; "e"; "e"; "e"];;
|
|
- : string list list =
|
|
[["a"; "a"; "a"; "a"]; ["b"]; ["c"; "c"]; ["a"; "a"]; ["d"; "d"];
|
|
["e"; "e"; "e"; "e"]]
|
|
#+end_src
|
|
|
|
**** Solution
|
|
#+begin_src ocaml
|
|
let rec pack list =
|
|
let rec f acc1 acc2 = function
|
|
| [] -> []
|
|
| [x] -> (x::acc1)::acc2
|
|
| x::(y::xs as tail) ->
|
|
if x = y
|
|
then f (x::acc1) acc2 tail
|
|
else f [] ((x::acc1)::acc2) tail
|
|
in f [] [] list |> List.rev
|
|
|
|
#+end_src
|
|
|