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> *)
| Expression | Result |
|---|---|
map List.hd rows | First column: [a; d] |
map List.tl rows | Remaining 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.