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

6.3 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

#11 Modified run-length encoding

Modify the result of the previous problem in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.

Since OCaml lists are homogeneous, one needs to define a type to hold both single elements and sub-lists.

type 'a rle =
  | One of 'a
  | Many of int * 'a

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

#12 Decode a run-length encoded list

Given a run-length code list generated as specified in the previous problem, construct its uncompressed version.

# decode [Many (4, "a"); One "b"; Many (2, "c"); Many (2, "a");
          One "d"; Many (4, "e")];;

- : string list =
["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "e"; "e"; "e"; "e"]
Solution