99-problems/README.org
2023-01-02 10:10:58 +07:00

4.8 KiB

99 Ocaml Problems

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

# last ["a" ; "b" ; "c" ; "d"];;
- : string option = Some "d"
                      # last [];;
- : 'a option = None
Solution
let rec last = function
  | []    -> None
  | [x]   -> Some x
  | _::xs -> last xs

#2 Last two elements of a list

Find the last but one (last and penultimate) elements of a list.

# last_two ["a"; "b"; "c"; "d"];;
- : (string * string) option = Some ("c", "d")
# last_two ["a"];;
- : (string * string) option = None
Solution
let rec last_two = function
  | [] | [_] -> None
  | [x;y] -> Some (x,y)
  | _::xs -> last_two xs

#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.

# List.nth ["a"; "b"; "c"; "d"; "e"] 2;;
- : string = "c"
# List.nth ["a"] 2;;
Exception: Failure "nth".
Solution
let rec nth index = function
  | [] -> failwith "nth"
  | x::xs -> if index = 0 then x else nth (index - 1) xs

#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.

# length ["a"; "b"; "c"];;
- : int = 3
# length [];;
- : int = 0
Solution
let length list =
  let rec length_rec acc = function
    | [] -> acc
    | _::xs -> length_rec (acc + 1) xs
  in length_rec 0 list

#5 Reverse a list.

OCaml standard library has List.rev but we ask that you reimplement it.

# rev ["a"; "b"; "c"];;
- : string list = ["c"; "b"; "a"]
Solution
let rev (list: int list) =
  let rec rev acc = function
    | [] -> acc
    | x::xs -> rev (x::acc) xs
  in rev [] list

#6 Palindrome

Find out whether a list is a palindrome.

HINT: a palindrome is its own reverse.

# is_palindrome ["x"; "a"; "m"; "a"; "x"];;
- : bool = true
# not (is_palindrome ["a"; "b"]);;
- : bool = true
Solution
let is_palindrome list = list = List.rev list

#7 Flatten a list

Flatten a nested list structure.

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"]
Solution
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

#8 Eliminate duplicates

Eliminate consecutive duplicates of list elements.

# compress ["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "e"; "e"; "e"; "e"];;
- : string list = ["a"; "b"; "c"; "a"; "d"; "e"]
Solution
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

#9 Pack consecutive duplicates

Pack consecutive duplicates of list elements into sublists.

# 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"]]
Solution
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

#10 Run-length encoding

If you need so, refresh your memory about run-length encoding.

Here is an example:

# encode ["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "e"; "e"; "e"; "e"];;
- : (int * string) list =
[(4, "a"); (1, "b"); (2, "c"); (2, "a"); (1, "d"); (4, "e")]
Solution
let encode = function
  | [] -> []
  | list ->
     let rec f (count, item) acc2 = function
       | [x] -> (count, item)::acc2
       | x::(y::xs as tail) when x = y -> f (count + 1, item) acc2 tail
       | x::(y::xs as tail) -> f (1, y) ((count, item)::acc2) tail
       | [] -> []
     in f (1, List.nth list 0) [] list |> List.rev