Skip to content
Part IA Michaelmas Term

Map and Matrix Operations

The map functional

map is the “apply to all” functional. It applies a function to every element of a list, returning a list of results:

let rec map f = function
  | [] -> []
  | x::xs -> (f x) :: map f xs
(* val map : ('a -> 'b) -> 'a list -> 'b list = <fun> *)

The type ('a -> 'b) -> 'a list -> 'b list shows that map transforms a function on elements into a function on lists.

Examples

map (fun s -> s ^ "ppy") ["Hi"; "Ho"]
(* => ["Hippy"; "Hoppy"] *)

map (map double) [[1]; [2; 3]]
(* => [[2]; [4; 6]] *)

Without map, the first example would require writing a dedicated recursive function. map captures the recursion pattern once and for all.

Matrix transpose

A matrix can be represented as a list of rows, where each row is a list of elements:

[[a; b; c]; [d; e; f]]
(* represents:  a b c
                 d e f   *)

The transpose function uses map with hd and tl:

let rec transp = function
  | []::_ -> []
  | rows -> (map List.hd rows) :: (transp (map List.tl rows))
(* val transp : 'a list list -> 'a list list = <fun> *)
ExpressionResult
map List.hd rowsFirst column: [a; d]
map List.tl rowsRemaining columns: [[b; c]; [e; f]]

The first column becomes the first row of the result. Recursion transposes the remaining columns. This is a concise definition that would otherwise require separate helper function declarations.

Matrix multiplication

The dot product of two vectors is computed by a curried function:

let rec dotprod xs ys =
  match xs, ys with
  | [], [] -> 0.0
  | x::xs, y::ys -> (x *. y) +. (dotprod xs ys)
(* val dotprod : float list -> float list -> float = <fun> *)

Because dotprod is curried, it can be partially applied to a single row. The matrix product then uses map:

let rec matprod arows brows =
  let cols = transp brows in
  map (fun row -> map (dotprod row) cols) arows
(* val matprod : float list list -> float list list -> float list list = <fun> *)

The inner map (dotprod row) cols computes the dot product of one row of A with every column of B. The outer map repeats this for every row of A. This is a compact replacement for the traditional triple-nested loop, avoiding subscript errors entirely.