Week 9: programming assignments from week 8

Q8.1

Question:

Write an OCaml function that will substitute all occurrences of an element in a list by a different element. The argument will have small-to-moderate size and performance considerations are not critical.

# replace;;
- : 'a -> 'a -> 'a list -> 'a list = <fun>
# replace 2 0 [1;2;3;4;3;2;1];;
- : int list = [1; 0; 3; 4; 3; 0; 1]

We found this in the tutorial:

let rec replace a b l = match l with
  | [] -> []
  | x :: xs -> if x = a
               then b :: (replace a b xs)
               else x :: (replace a b xs)

Model solution: https://github.com/Duta/focs-2015-16/blob/master/solutions/week-8/exercise-1/wk8ex1.ml

Q8.2

Question:

Write an OCaml function that splits a list into list segments containing only identical elements. The function must work on small-to-moderate size lists. Performance of implementation is not critical.

# split;;
- : 'a list -> 'a list list = <fun>
# split [1;2;2;3;3;3;4;4;5;6];;
- : int list list = [[1]; [2; 2]; [3; 3; 3]; [4; 4]; [5]; [6]]
# split [];;
- : 'a list list = []
# split [1];;
- : int list list = [[1]]
# split [1;2;3;3;2;2;1;1];;
- : int list list = [[1]; [2]; [3; 3]; [2; 2]; [1; 1]]

We found this in the tutorial:

let rec split l = match l with
      | [] -> []
      | x :: xs -> let ys = split xs in
                   match ys with
                   | [] -> [[x]]
                   | z :: zs -> if x = List.hd z then (x :: z) :: zs
                                else [x] :: ys
                            ;;

Model solution: https://github.com/Duta/focs-2015-16/tree/master/solutions/week-8/exercise-2

Q8.3a

Question:

You are given two lists that have as elements either integers or characters. The characters stand for variables of unknown values. You need to solve the following puzzle: Is there a way to give values to variables so that the two lists are equal?

For example [x, 1, x] and [3, y, 3] is solvable for x = 3 and y = 1 whereas [x, x, 0] and [1, 2, z] is not solvable.

Your task is to write an OCaml function that checks whether a puzzle is solvable or not.

type puzzle = K of int | U of char

# solvable;;
- : puzzle list -> puzzle list -> bool = <fun>

# solvable [U 'x'; K 1; U 'x'] [K 3; U 'y'; K 3] ;;
- : bool = true
# solvable [U 'x'; U 'x'; K 0] [K 1; K 2; U 'z'];;
- : bool = false

Model solution: https://github.com/Duta/focs-2015-16/tree/master/solutions/week-8/exercise-3a


In the below solutions, I have fixed a bug since the tutorial.

We found this in the tutorial:

let rec solvable xs ys = match xs, ys with
  | [], [] -> true
  | [], (c :: cs) -> false
  | (b :: bs), [] -> false
  | (b :: bs), (c :: cs) ->
      match b, c with
       | K b', K c' -> (b' = c') && (solvable bs cs)
       | U b', K c' -> solvable (replace (U b') (K c') bs) (replace (U b') (K c') cs)
       | K b', U c' -> solvable (replace (U c') (K b') bs) (replace (U c') (K b') cs)
       | U b', U c' -> solvable (replace (U b') (U c') bs) (replace (U b') (U c') cs);;

Alternatively, this:

let rec solvable xs ys = match xs, ys with
  | [], [] -> true
  | [], (c :: cs) -> false
  | (b :: bs), [] -> false
  | (b :: bs), (c :: cs) ->
      match b, c with
       | K b', K c' -> (b' = c') && (solvable bs cs)
       | U b', K c' -> solvable (replace (U b') c bs) (replace (U b') c cs)
       | K b', U c' -> solvable (replace (U c') b bs) (replace (U c') b cs)
       | U b', U c' -> solvable (replace (U b') c bs) (replace (U b') c cs);;

Alternatively, this:

let rec solvable xs ys = match xs, ys with
  | [], [] -> true
  | [], (c :: cs) -> false
  | (b :: bs), [] -> false
  | (b :: bs), (c :: cs) ->
      match b, c with
       | K b', K c' -> (b' = c') && (solvable bs cs)
       | U b', _ -> solvable (replace (U b') c bs) (replace (U b') c cs)
       | _, U c' -> solvable (replace (U c') b bs) (replace (U c') b cs);;

In a sense, this is nicer because we have fewer cases. But it’s a matter of taste.

Alternatively, this:

let rec solvable xs ys = match xs, ys with
  | [], [] -> true
  | [], (c :: cs) -> false
  | (b :: bs), [] -> false
  | (b :: bs), (c :: cs) ->
      match b with
       | K b' -> (match c with
                  | U c' -> solvable (replace (U c') (K b') bs) (replace (U c') (K b') cs)
                  | K c' -> b' = c' && (solvable bs cs))
       | U b' -> solvable (replace (U b') c bs) (replace (U b') c cs);;

(In the last program, I had to add parentheses around the inner match otherwise OCaml would think that | U b' belonged to the inner match.)