Compare commits
10 Commits
f9ae8e8354
...
83408ddc5d
Author | SHA1 | Date | |
---|---|---|---|
83408ddc5d | |||
c62dcd31bb | |||
1c60de9818 | |||
5af66cc89d | |||
449d4cd81f | |||
eeda1f3b72 | |||
6a59fdf97f | |||
e869be4852 | |||
7615f5ebc9 | |||
04c981b892 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/Test.hs
|
90
Haskell.org
Normal file
90
Haskell.org
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#+TITLE: 99 Haskell Problems
|
||||||
|
#+Author: Joseph Ferano
|
||||||
|
|
||||||
|
https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems
|
||||||
|
|
||||||
|
*** #1 Find the last element of a list.
|
||||||
|
|
||||||
|
#+begin_src haskell
|
||||||
|
λ> myLast [1,2,3,4]
|
||||||
|
4
|
||||||
|
λ> myLast ['x','y','z']
|
||||||
|
'z'
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
**** Solution
|
||||||
|
#+begin_src haskell
|
||||||
|
myLast [] = error "Cannot accept an empty list"
|
||||||
|
myLast [x] = x
|
||||||
|
myLast (_:xs) = myLast xs
|
||||||
|
|
||||||
|
myLast [1..5]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** #2 Find the last but one element of a list.
|
||||||
|
|
||||||
|
#+begin_src haskell
|
||||||
|
λ> myButLast [1,2,3,4]
|
||||||
|
3
|
||||||
|
λ> myButLast ['a'..'z']
|
||||||
|
'y'
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
**** Solution
|
||||||
|
#+begin_src haskell
|
||||||
|
myButLast x
|
||||||
|
| length x < 2 = error "Cannot accept an empty list"
|
||||||
|
| otherwise = case x of
|
||||||
|
[x,y] -> x
|
||||||
|
(x:xs) -> myButLast xs
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** #3 Find the K'th element of a list.
|
||||||
|
|
||||||
|
The first element in the list is number 1.
|
||||||
|
|
||||||
|
#+begin_src haskell
|
||||||
|
λ> elementAt [1,2,3] 2
|
||||||
|
2
|
||||||
|
λ> elementAt "haskell" 5
|
||||||
|
'e'
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
**** Solution
|
||||||
|
#+begin_src haskell
|
||||||
|
elementAt (x:xs) i = if i == 1 then x else elementAt xs (i - 1)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** #4 Find the number of elements of a list.
|
||||||
|
|
||||||
|
#+begin_src haskell
|
||||||
|
λ> myLength [123, 456, 789]
|
||||||
|
3
|
||||||
|
λ> myLength "Hello, world!"
|
||||||
|
13
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
**** Solution
|
||||||
|
|
||||||
|
#+begin_src haskell
|
||||||
|
myLength [] = 0
|
||||||
|
myLength xs = foldl (\acc _ -> acc + 1) 0 xs
|
||||||
|
-- or
|
||||||
|
myLength' [] = 0
|
||||||
|
myLength' [x] = 1
|
||||||
|
myLength' (_:xs) = 1 + myLength xs
|
||||||
|
|
||||||
|
myLength [1..5]
|
||||||
|
myLength' [1..5]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
: 5
|
||||||
|
|
20
LICENSE
Normal file
20
LICENSE
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2023 Joseph Ferano - joseph@ferano.io
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
383
OCaml.org
Normal file
383
OCaml.org
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
#+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
|
||||||
|
|
||||||
|
|
||||||
|
*** #10 Run-length encoding
|
||||||
|
|
||||||
|
If you need so, refresh your memory about run-length encoding.
|
||||||
|
|
||||||
|
Here is an example:
|
||||||
|
|
||||||
|
#+begin_src ocaml
|
||||||
|
# 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")]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** Solution
|
||||||
|
#+begin_src ocaml
|
||||||
|
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
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** #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.
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src ocaml
|
||||||
|
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")]
|
||||||
|
#+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
|
||||||
|
|
||||||
|
let encode list =
|
||||||
|
let packed = pack list
|
||||||
|
in packed |>
|
||||||
|
List.map (function
|
||||||
|
| [] -> invalid_arg "List should not be empty"
|
||||||
|
| [x] -> One x
|
||||||
|
| x::xs as l -> Many (List.length l, x))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** #12 Decode a run-length encoded list
|
||||||
|
|
||||||
|
Given a run-length code list generated as specified in the previous problem,
|
||||||
|
construct its uncompressed version.
|
||||||
|
|
||||||
|
#+begin_src ocaml
|
||||||
|
# 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"]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** Solution
|
||||||
|
#+begin_src ocaml
|
||||||
|
let decode list =
|
||||||
|
let rec f acc = function
|
||||||
|
| [] -> acc
|
||||||
|
| One c::tail -> f (c::acc) tail
|
||||||
|
| Many (n, c)::tail when n > 1 -> f (c::acc) (Many(n-1,c)::tail)
|
||||||
|
| Many (_, c)::tail -> f (c::acc) tail
|
||||||
|
in f [] list |> List.rev
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** #13 Run-length encoding of a list (direct solution)
|
||||||
|
|
||||||
|
Implement the so-called run-length encoding data compression method
|
||||||
|
directly. I.e. don't explicitly create the sublists containing the duplicates,
|
||||||
|
as in problem "Pack consecutive duplicates of list elements into sublists", but
|
||||||
|
only count them. As in problem "Modified run-length encoding", simplify the
|
||||||
|
result list by replacing the singleton lists (1 X) by X.
|
||||||
|
|
||||||
|
#+begin_src ocaml
|
||||||
|
# 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")]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** Solution
|
||||||
|
#+begin_src ocaml
|
||||||
|
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
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** #14 Duplicate the elements of a list
|
||||||
|
|
||||||
|
Duplicate the elements of a list.
|
||||||
|
|
||||||
|
#+begin_src ocaml
|
||||||
|
# duplicate ["a"; "b"; "c"; "c"; "d"];;
|
||||||
|
- : string list = ["a"; "a"; "b"; "b"; "c"; "c"; "c"; "c"; "d"; "d"]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** Solution
|
||||||
|
#+begin_src ocaml
|
||||||
|
let duplicate list =
|
||||||
|
let rec f acc = function
|
||||||
|
| [] -> acc
|
||||||
|
| x::xs -> f (x::x::acc) xs
|
||||||
|
in f [] list |> List.rev
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** #15 Replicate the elements of a list a given number of times
|
||||||
|
|
||||||
|
Replicate the elements of a list a given number of times.
|
||||||
|
|
||||||
|
#+begin_src ocaml
|
||||||
|
# replicate ["a"; "b"; "c"] 3;;
|
||||||
|
- : string list = ["a"; "a"; "a"; "b"; "b"; "b"; "c"; "c"; "c"]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** Solution
|
||||||
|
#+begin_src ocaml
|
||||||
|
let replicate list num =
|
||||||
|
let rec f (count, acc) = function
|
||||||
|
| [] -> acc
|
||||||
|
| x::xs when count <= 1 -> f (num, x::acc) xs
|
||||||
|
| (x::_ as l) -> f (count - 1, x::acc) l
|
||||||
|
in f (num,[]) list |> List.rev
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
*** #16 Drop every N'th element from a list
|
||||||
|
|
||||||
|
Drop every N'th element from a list.
|
||||||
|
|
||||||
|
#+begin_src ocaml
|
||||||
|
# drop ["a"; "b"; "c"; "d"; "e"; "f"; "g"; "h"; "i"; "j"] 3;;
|
||||||
|
- : string list = ["a"; "b"; "d"; "e"; "g"; "h"; "j"]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** Solution
|
||||||
|
#+begin_src ocaml
|
||||||
|
let drop list num =
|
||||||
|
let rec f (count, acc) = function
|
||||||
|
| [] -> acc
|
||||||
|
| x::xs when count = 1 -> f (num, acc) xs
|
||||||
|
| x::xs -> f (count-1, x::acc) xs
|
||||||
|
in f (num,[]) list |> List.rev
|
||||||
|
#+end_src
|
214
README.org
214
README.org
@ -1,203 +1,21 @@
|
|||||||
#+TITLE: 99 Ocaml Problems
|
#+OPTIONS: toc:nil
|
||||||
#+Author: Joseph Ferano
|
|
||||||
|
|
||||||
https://ocaml.org/problems
|
* About
|
||||||
|
|
||||||
*** #1 Tail of a list
|
This repository contains my ongoing solutions for both OCaml and Haskell coding
|
||||||
|
challenge problems in the style of "99 Problems". See below for references. The
|
||||||
|
intention is to practice these languages in the hopes of someday using them in
|
||||||
|
anger. The solutions use a style of programming known as [[https://en.wikipedia.org/wiki/Literate_programming][Literate Programming]]
|
||||||
|
with the help of Emacs, org-mode, and [[https://orgmode.org/worg/org-contrib/babel/intro.html][org-babel]]. All code is executable from
|
||||||
|
within Emacs by just running ~C-c C-c~ while the cursor is in the source code
|
||||||
|
block.
|
||||||
|
|
||||||
Write a function ~last : 'a list -> 'a option~ that returns the last element of a
|
* Progress
|
||||||
list
|
- [16/99] OCaml
|
||||||
|
- [4/99] Haskell
|
||||||
|
- [0/99] Lisp (Soon)
|
||||||
|
|
||||||
#+begin_src ocaml
|
* References
|
||||||
# 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
|
|
||||||
|
|
||||||
|
- OCaml Exercises: https://ocaml.org/problems
|
||||||
|
- 99 Haskell Problems: https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems
|
||||||
|
Loading…
x
Reference in New Issue
Block a user