0% found this document useful (0 votes)
29 views

Functional Programming PDF

Functional Programming by TyngRuey Chuang

Uploaded by

Mr.Syed
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views

Functional Programming PDF

Functional Programming by TyngRuey Chuang

Uploaded by

Mr.Syed
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 21

Functional Programming

Tyng–Ruey Chuang

2010 Formosan Summer School


on Logic, Language, and Computation
June 28 – July 9, 2010

This course note . . .

• . . . is prepared for the 2010 Formosan Summer School on Logic, Language, and Com-
putation (FLOLAC) held in Taipei, Taiwan,

• . . . is made available from the FLOLAC ’10 web site:

http://flolac.iis.sinica.edu.tw/flolac10/

(please also check the above site for updated version)

• . . . and is released to the public under a Creative Commons Attribution-ShareAlike


3.0 Taiwan license:

http://creativecommons.org/licenses/by-sa/3.0/

Course outline

Unit 1. Basics of functional programming.

Unit 2. Fold/unfold functions; Parametric modules.

Each unit consists of 2 hours of lecture and 1 hour of lab/tutor. Examples will be given
in Objective Caml (O’Caml). Useful online resources about O’Caml:

• Web site: http://caml.inria.fr/

• Book: Developing Applications with Objective Caml.


URL: http://caml.inria.fr/pub/docs/oreilly-book/

1
1 Basics of functional programming
1.1 Function, evaluation, and binding
Functions
let x = 1
let y = x + 1
let succ n = n + 1
let z = succ y
• val x : int = 1
val y : int = 2
val succ : int -> int = <fun>
val z : int = 3
let sum x y = x + y
let five = sum 2 3
• val sum : int -> int -> int = <fun>
val five : int = 5
let plus3 = sum 3
let seven = plus3 4
• val plus3 : int -> int = <fun>
val seven : int = 7

Anonymous functions
let succ = fun n -> n + 1
let one = succ 0
let two = (fun n -> n + 1) one
• val succ : int -> int = <fun>
val one : int = 1
val two : int = 2
let sum = fun x -> fun y -> x + y
let plus3 = sum 3
• val sum : int -> int -> int = <fun>
val plus3 : int -> int = <fun>
let twice = fun f -> fun x -> f (f x)
let plus6 = twice plus3
let seven = plus6 one
• val twice : (’a -> ’a) -> ’a -> ’a = <fun>
val plus6 : int -> int = <fun>
val seven : int = 7

2
Functions as arguments and as results
let compose f g = fun x -> f (g x)
let plus3 n = n + 3
let times2 n = n * 2
let this = compose plus3 times2 1
let that = compose times2 plus3 1
• val compose : (’a -> ’b) -> (’c -> ’a) -> ’c -> ’b = <fun>
val plus3 : int -> int = <fun>
val times2 : int -> int = <fun>
val this : int = 5
val that : int = 8

let twice f = compose f f


let what = twice (fun n -> n + n)
let guess = what 1
• val twice : (’a -> ’a) -> ’a -> ’a = <fun>
val what : int -> int = <fun>
val guess : int = 4

Notations in O’Caml
Function application is just juxtaposition, and is left associative. These two definitions
are the same:
• let this = compose plus3 times2 1
• let this = ((compose plus3) times2) 1
Function abstraction is right associative. These two definitions are the same:
• let sum = fun x -> fun y -> x + y

val sum : int -> int -> int = <fun>

• let sum = fun x -> (fun y -> x + y)

val sum : int -> (int -> int) = <fun>

Evaluation in O’Caml
• Expressions are evaluated before they are passed as arguments to the function body.
• The function body is evaluated only when all the arguments are evaluated.
• Functions can be partially applied.

3
Binding in O’Caml

• Lexical binding: Expressions are evaluated and bound to the corresponding identifiers
in the order they appear in the program text.
• Nested binding: Outer bindings are shadowed by inner bindings.

let x = 100
let f y = let x = x + y in x
let x = 10
let z = f x

• Simultaneous binding: Several bindings occur at the same time under the same envi-
ronment.

let x = z
and z = x

• Recursive binding: Identifiers can be referred to when they are being defined.

let rec fac n = if n <= 0 then 1 else n * (fac (n -1))


let six = fac 3

Recursive functions: examples

• Expressiveness: Euclid’s algorithm for greatest common divisor (gcd), assuming inte-
gers m, n > 0:

let rec gcd m n =


if m mod n = 0
then n
else gcd n (m mod n)

let u = gcd 57 38
let v = gcd 38 59

• The danger of non-terminating computation:

let rec loop x = loop x


let oops = loop 0

4
1.2 Data types
Built-in data types in O’Caml

type int 0, -1, . . .

type char ’a’, ’\’’, . . .

type string "\"O’Caml\" is a fine language.\n", . . .

type float 3.14159, 0.314159e1, . . .

type unit = ()

type bool = false | true

type ’a list = [] | :: of ’a * ’a list [], true::false::[], [1; 2; 3], . . .

type ’a option = None | Some of ’a None, Some 17, Some [None; Some true], . . .

Built-in type operators in O’Caml

Cartesian product

type int_pair = int * int

let rec gcd (m, n) =


if m mod n = 0
then n else gcd (n, m mod n)

val gcd : int * int -> int = <fun>

Function space

type int2int2int = int -> int -> int

let rec gcd m n =


if m mod n = 0
then n else gcd n (m mod n)

val gcd : int -> int -> int = <fun>

5
Expressions, values, and types

• Well-typed expressions:

0, (1 + 2), (sum 2 3), (fun x -> fun y -> x + y), (2, true)

• Ill-typed expressions:

(1 + ’2’), (sum 2 3.0), ((fun x -> fun y -> x + y) 0 1 2)

• All O’Caml values have types:

val sum : int -> int -> int = <fun>


val five : int = 5

• Some values are polymorphic:

val twice : (’a -> ’a) -> ’a -> ’a = <fun>


val empty_list : ’a list = []

• Expressions are statically checked to ensure they always evaluate to values.

O’Caml is strict

• O’Caml insists on evaluating the arguments in a function application though the ar-
guments may not be required for the computation in the function body. O’Caml is
called a strict language.

• Some functional language, e.g., Haskell, will evaluate the function arguments only
when they are demanded by the computation in the function body. These languages
are non-strict.
• What is wrong in this picture (in O’Caml):

let oracle () = ...

let choice this that =


if oracle () then this else that

• let rec loop x = loop x


let oops = choice (loop 0) 0

6
Functions to the rescue!
let rec loop x = loop x

let choice this that =


if oracle () then this else that

let new_choice this that =


if oracle () then this () else that ()

let was = choice (loop 0) 0


let now = new_choice (fun () -> loop 0) (fun () -> 0)

val choice : ’a -> ’a -> ’a = <fun>


val new_choice : (unit -> ’a) -> (unit -> ’a) -> ’a = <fun>

What about variables?


• We can bind values to identifiers; once an identifier is bound, its value never changes.
Of course, bindings can be nested hence, for the same identifier, the inner binding may
shadow outer binding.
• Can one implement a counter using only functions?
• We can implement many counters using only functions!
• let init value = fun () -> value
let read counter = counter ()
let step counter more = fun () -> read counter + more

val init : ’a -> unit -> ’a = <fun>


val read : (unit -> ’a) -> ’a = <fun>
val step : (unit -> int) -> int -> unit -> int = <fun>

Counters via functions


let init value = fun () -> value
let read counter = counter ()
let step counter more = fun () -> read counter + more

let mem = init 0


let x = step mem 1
let y = step mem 2
let z = step x 100
let x_y_z = (read x, read y, read z)

7
val init : ’a -> unit -> ’a = <fun>
val read : (unit -> ’a) -> ’a = <fun>
val step : (unit -> int) -> int -> unit -> int = <fun>
val mem : unit -> int = <fun>
val x : unit -> int = <fun>
val y : unit -> int = <fun>
val z : unit -> int = <fun>
val x_y_z : int * int * int = (1, 2, 101)

Programming by pattern-matching

type ’a table = (string * ’a) list

let rec lookup key table =


match table with
[] -> None
| (name, value) :: rest ->
if key = name then Some value
else lookup key rest

type color = Red | Yellow | Green


let fruits = [("banana", Yellow); ("guava", Green)]

let this = lookup "guava" fruits


let that = lookup "mango" fruits

val lookup : ’a -> (’a * ’b) list -> ’b option = <fun>


val fruits : (string * color) list = [("banana", Yellow); ("guava", Green)]
val this : color option = Some Green
val that : color option = None

List reversal: two examples

• let rec reverse list =


match list with
[] -> []
| head :: tail -> (reverse tail) @ [head]

• let reverse list =


let rec rev rest accumulator =
match rest with
[] -> accumulator
| hd :: tl -> rev tl (hd :: accumulator)
in
rev list []

8
• Both have type:

val reverse : ’a list -> ’a list = <fun>

• Which one is better?

Functions over lists

let rec filter p list =


match list with
[] -> []
| head :: tail -> if p head then head :: (filter p tail)
else filter p tail

let rec append front rear =


match front with
[] -> rear
| head :: tail -> head :: (append tail rear)

let this = filter (fun n -> n mod 2 = 0) [1; 2; 3]


let that = append [1; 2; 3] [100; 101; 102]

val filter : (’a -> bool) -> ’a list -> ’a list = <fun>
val append : ’a list -> ’a list -> ’a list = <fun>
val this : int list = [2]
val that : int list = [1; 2; 3; 100; 101; 102]

User-defined type constructors

type ’a tree = Leaf


| Node of ’a * ’a tree * ’a tree

• tree is a type constructor: it construct a type α tree whenever given a type α.


• Leaf and Node are the two value constructors for type α tree.

Leaf: ’a tree
Node: ’a * ’a tree * ’a tree -> ’a tree

• In O’Caml, type constructors start with lower-case letters; value constructors start
with upper-case letters.

9
• In O’Caml, type constructors and value constructors are unary. Type construction
uses postfix notation; value construction, prefix.

Some (Node (1, Node (0, Leaf, Leaf), Node (2, Leaf, Leaf)))

has type

int tree option

Functions over trees


let rec swap tree =
match tree with
Leaf -> Leaf
| Node (here, left, right) ->
Node (here, swap right, swap left)

let rec insert key tree =


match tree with
Leaf -> Node (key, Leaf, Leaf)
| Node (here, left, right) ->
if key < here
then Node (here, insert key left, right)
else Node (here, left, insert key right)

val swap : ’a tree -> ’a tree = <fun>


val insert : ’a -> ’a tree -> ’a tree = <fun>

Functions over trees, continued


let rec build f s =
match f s with
None -> Leaf
| Some (a, left, right) ->
Node (a, build f left, build f right)

let range (low, high) =


if low > high
then None
else let mid = (low + high) / 2 in
Some (mid, (low, mid - 1), (mid + 1, high))

let tree1to7 = build range (1, 7)

10
val build : (’a -> (’b * ’a * ’a) option) -> ’a -> ’b tree = <fun>
val range : int * int -> (int * (int * int) * (int * int)) option = <fun>
val tree1to7 : int tree = Node (4, Node (2, Node (1, Leaf, Leaf), Node (3, Leaf, Leaf)),
Node (6, Node (5, Leaf, Leaf), Node (7, Leaf, Leaf)))

2 Fold/unfold functions; Parametric modules


2.1 Fold/unfold functions for data types
Functions over lists, re-visited
let rec filter p list =
match list with
[] -> []
| head :: tail ->
if p head then head :: (filter p tail)
else filter p tail

let rec append front rear =


match front with
[] -> rear
| head :: tail -> head :: (append tail rear)

• Both functions work on lists in a bottom-up manner.


• What is the base case, and what is the inductive step?

Fold function for lists


let rec fold (base, step) list =
match list with
[] -> base
| hd :: tl -> step (hd, fold (base, step) tl)

let filter p list =


let step (hd, acc) = if p hd then (hd :: acc) else acc
in
fold ([], step) list

let append front rear =


fold (rear, fun (hd, acc) -> hd :: acc) front

val fold : ’a * (’b * ’a -> ’a) -> ’b list -> ’a = <fun>


val filter : (’a -> bool) -> ’a list -> ’a list = <fun>
val append : ’a list -> ’a list -> ’a list = <fun>

11
Fold function for trees
let rec swap tree =
match tree with
Leaf -> Leaf
| Node (here, left, right) ->
Node (here, swap right, swap left)

let rec fold (base, step) tree =


match tree with
Leaf -> base
| Node (here, left, right) ->
step (here, fold (base, step) left,
fold (base, step) right)

let swap’ tree = fold (Leaf,


fun (here, left, right) -> Node (here, right, left)) tree

val fold : ’b * (’a * ’b * ’b -> ’b) -> ’a tree -> ’b = <fun>

What is a tree, anyway?


fold : ’b * (’a * ’b * ’b -> ’b) -> ’a tree -> ’b
• A tree of type α tree is a value that can be folded.
• Whenever given a base value of type β, and an inductive function of type α×β ×β → β,
a tree can be folded into a value of type β.

A new data type for trees


type (’a, ’b) t = Leaf
| Node of ’a * ’b * ’b

type ’a tree = Rec of (’a, ’a tree) t

let rec fold f tree =


match tree with
Rec Leaf -> f Leaf
| Rec (Node (here, left, right)) ->
f (Node (here, fold f left, fold f right))

type (’a, ’b) t = Leaf | Node of ’a * ’b * ’b


type ’a tree = Rec of (’a, ’a tree) t
val fold : ((’a, ’b) t -> ’b) -> ’a tree -> ’b = <fun>

12
A new swap function
let swap tree =
let f t = match t with Leaf -> Rec Leaf
| Node (here, left, right) ->
Rec (Node (here, right, left))
in
fold f tree

let tree123 = Rec (Node (2, Rec (Node (1, Rec Leaf, Rec Leaf)),
Rec (Node (1, Rec Leaf, Rec Leaf))))
let tree321 = swap tree123

val swap : ’a tree -> ’a tree = <fun>


val tree123 : int tree =
Rec (Node (2, Rec (Node (1, Rec Leaf, Rec Leaf)),
Rec (Node (1, Rec Leaf, Rec Leaf))))
val tree321 : int tree =
Rec (Node (2, Rec (Node (1, Rec Leaf, Rec Leaf)),
Rec (Node (1, Rec Leaf, Rec Leaf))))

Look at a tree this way!


type (’a, ’b) t = Leaf | Node of ’a * ’b * ’b

type ’a tree = Rec of (’a, ’a tree) t

val fold : ((’a, ’b) t -> ’b) -> ’a tree -> ’b = <fun>
• Type constructor (α, β) t defines (the only) two forms of a tree node.
• Type constructor α tree defines a tree as a recursive structure via type constructor
(α, β) t. The recursion occurs at the second type argument to t.
• A function of type (α, β) t → β comprises both the base case and the inductive step
necessary for folding a value of type α tree to a value of type β.

A new data type for trees, continued


type (’a, ’b) t = Leaf
| Node of ’a * ’b * ’b

type ’a tree = Rec of (’a, ’a tree) t

let rec unfold g seed =


match g seed with
Leaf -> Rec Leaf
| Node (here, left, right) ->
Rec (Node (here, unfold g left, unfold g right))

13
type (’a, ’b) t = Leaf | Node of ’a * ’b * ’b
type ’a tree = Rec of (’a, ’a tree) t
val unfold : (’a -> (’b, ’a) t) -> ’a -> ’b tree = <fun>

We saw this before!

let rec build f s =


match f s with
None -> Leaf
| Some (a, left, right) ->
Node (a, build f left, build f right)

let range (low, high) =


if low > high
then None
else let mid = (low + high) / 2 in
Some (mid, (low, mid - 1), (mid + 1, high))

let tree1to7 = build range (1, 7)

val build : (’a -> (’b * ’a * ’a) option) -> ’a -> ’b tree = <fun>
val range : int * int -> (int * (int * int) * (int * int)) option = <fun>
val tree1to7 : int tree = Node (4, Node (2, Node (1, Leaf, Leaf), Node (3, Leaf, Leaf)),
Node (6, Node (5, Leaf, Leaf), Node (7, Leaf, Leaf)))

Rewrite it using unfold

let rec unfold g seed =


match g seed with
Leaf -> Rec Leaf
| Node (here, left, right) ->
Rec (Node (here, unfold g left, unfold g right))

let range (low, high) =


if low > high
then Leaf
else let mid = (low + high) / 2 in
Node (mid, (low, mid - 1), (mid + 1, high))

let balanced = unfold range


let tree1to7 = balanced (1, 7)

val unfold : (’a -> (’b, ’a) t) -> ’a -> ’b tree = <fun>
val range : int * int -> (int, int * int) t = <fun>
val balanced : int * int -> int tree = <fun>
val tree1to7 : ...

14
Look at a tree the other way!
type (’a, ’b) t = Leaf | Node of ’a * ’b * ’b

type ’a tree = Rec of (’a, ’a tree) t

val unfold : (’b -> (’a, ’b) t) -> ’b -> ’a tree = <fun>
• Type constructor (α, β) t defines (the only) two forms of a tree node.
• Type constructor α tree defines a tree as a recursive structure via type constructor
(α, β) t. The recursion occurs at the second type argument to t.
• A function of type β → (α, β) t comprises the co-inductive step necessary for unfolding
a value of type β to a value of type α tree.

Fold and unfold for trees


let rec fold f tree =
match tree with
Rec Leaf -> f Leaf
| Rec (Node (here, left, right)) ->
f (Node (here, fold f left, fold f right))

let rec unfold g seed =


match g seed with
Leaf -> Rec Leaf
| Node (here, left, right) ->
Rec (Node (here, unfold g left, unfold g right))
val fold : ((’a, ’b) t -> ’b) -> ’a tree -> ’b = <fun>
val unfold : (’a -> (’b, ’a) t) -> ’a -> ’b tree = <fun>

Functions fold and unfold look strangely similar to each other!

Fold and unfold for trees, the third round (I)


type (’a, ’b) t = Leaf
| Node of ’a * ’b * ’b

let map (f, g) t =


match t with Leaf -> Leaf
| Node (h, l, r) -> Node (f h, g l, g r)

type ’a tree = Rec of (’a, ’a tree) t

let down (Rec t) = t


let up t = Rec t

15
val map : (’a->’b) * (’c->’d) -> (’a,’c) t -> (’b,’d) t = <fun>
val down : ’a tree -> (’a, ’a tree) t = <fun>
val up : (’a, ’a tree) t -> ’a tree = <fun>

Fold and unfold for trees, the third round (II)

type (’a, ’b) t = Leaf


| Node of ’a * ’b * ’b

type ’a tree = Rec of (’a, ’a tree) t

let id x = x

let rec fold f tree = f (map (id, fold f) (down tree))

let rec unfold g seed = up (map (id, unfold g) ( g seed))

val id : ’a -> ’a = <fun>


val fold : ((’a, ’b) t -> ’b) -> ’a tree -> ’b = <fun>
val unfold : (’a -> (’b, ’a) t) -> ’a -> ’b tree = <fun>

Fold and unfold for trees — ever more functional!


Fold and unfold are functions that each takes in a (basis) function as the argument and
return a (tree) function as the result.

let ($) f g x = f (g x)

let rec fold f tree = (f $ map (id, fold f) $ down) tree


let rec unfold g seed = (up $ map (id, unfold g) $ g) seed

let this = fold up


let that = unfold down

val ( $ ) : (’a -> ’b) -> (’c -> ’a) -> ’c -> ’b = <fun>
val fold : ((’a, ’b) t -> ’b) -> ’a tree -> ’b = <fun>
val unfold : (’a -> (’b, ’a) t) -> ’a -> ’b tree = <fun>
val this : ’a tree -> ’a tree = <fun>
val that : ’a tree -> ’a tree = <fun>

What is this, and what is that?

16
Functional diagram for fold
In the diagram, functions are arrows, and types are objects.

down -
α tree (α, α tree) t

fold f map (id, fold f )


? f ?
β (α, β) t

let rec fold f tree = (f $ map (id, fold f) $ down) tree

Functional diagram for unfold


In the diagram, functions are arrows, and types are objects.

g
β - (α, β) t

unfold f map (id, unfold f )


? up ?
α tree  (α, α tree) t

let rec unfold g seed = (up $ map (id, unfold g) $ g) seed

Let’s not forget lists!

type (’a, ’b) t = Null


| Cons of ’a * ’b

type ’a list = Rec of (’a, ’a list) t

let rec fold f list = (f $ map (id, fold f) $ down) list


let rec unfold g seed = (up $ map (id, unfold g) $ g) seed

down g
α list - (α, α list) t β - (α, β) t

fold f map (id, fold f ) unfold f map (id, unfold f )


? f ? ? up ?
β (α, β) t α list  (α, α list) t

17
2.2 Parametric Modules
Modules

• A module, also called structure, packs together related definitions (types, values, and
even modules).

• The module name acts as a “name space” to avoid name conflicts.

module MyStack =
struct
type ’a t = ’a list
let empty = []
let push elm stack = elm :: stack
let pop stack =
match stack with
[] -> None
| head :: tail -> Some (head, tail)
end

let whatever = MyStack.push 1 []

Module interfaces

• A module interface, also called signature, specifies which components of a structure


are accessible from the outside, and with which type.

• It acts as a contract between the user and the implementer of a module. Interface
checking is always enforced in O’Caml.

module type STACK =


sig
type ’a t
val empty: ’a t
val push: ’a -> ’a t -> ’a t
val pop: ’a t -> (’a * ’a t) option
end

module S: STACK = MyStack


let whatever = S.push 1 S.empty

Parametric modules

• A parametric module, also called functor, is a structure parameterized by other struc-


tures.

18
• Type sharing and structure sharing constraints can be used to relate the arguments
and the result.

module type QUEUE = STACK


module type S2Q = functor (S: STACK) -> QUEUE

module MakeQueue: S2Q = functor (S: STACK) ->


struct
type ’a t = ’a S.t * ’a S.t
let empty = (S.empty, S.empty)
let push elm (front, rear) = (front, S.push elm rear)
let pop (front, rear) =
match S.pop front with
Some (e, s) -> Some (e, (s, rear))
| None -> ...
end

Tree folding

type (’a, ’b) t = Leaf


| Node of ’a * ’b * ’b

let map (f, g) t =


match t with Leaf -> Leaf
| Node (h, l, r) -> Node (f h, g l, g r)

type ’a tree = Rec of (’a, ’a tree) t

down -
α tree (α, α tree) t

fold f map (id, fold f )


? f ?
β (α, β) t

List folding

type (’a, ’b) t = Null


| Cons of ’a * ’b

let map (f, g) t =


match t with Null -> Null

19
| Cons (hd, tl) -> Cons (f hd, g tl)

type ’a list = Rec of (’a, ’a list) t

down -
α list (α, α list) t

fold f map (id, fold f )


? f ?
β (α, β) t

A fold for all seasons?

• Wanted: A way to describe the derivation of a unary type constructor by recursing


over a binary type constructor, and to define the accompanying fold function at the
same time.

• This is exactly what a parametric module can do!

• Input: a module with a binary type constructor and its map function.

• Output: a module with a unary type constructor, its map function, and its fold and
unfold functions.

Module interfaces FUN and FIX

module type FUN =


sig
type (’a, ’u) t
val map: (’a -> ’b) * (’u -> ’v) -> (’a, ’u) t -> (’b, ’v) t
end

module type FIX =


sig
module Base: FUN
type ’a t = Rec of (’a, ’a t) Base.t
val down: ’a t -> (’a, ’a t) Base.t
val up: (’a, ’a t) Base.t -> ’a t

val map: (’a -> ’b) -> ’a t -> ’b t


val fold: ((’a, ’x) Base.t -> ’x) -> ’a t -> ’x
end

20
Mu, the fixed-pointing module

module type MU = functor (B: FUN) -> FIX with module Base = B

module Mu: MU = functor (B: FUN) ->


struct
module Base = B
type ’a t = Rec of (’a, ’a t) Base.t
let down (Rec t) = t
let up t = Rec t

let rec fold f (Rec t) = f (Base.map (id, fold f) t)


let rec map f (Rec t) = Rec (Base.map (f, map f) t)
end

Module Tree

module T =
struct
type (’a, ’b) t = Leaf
| Node of ’a * ’b * ’b

let map (f, g) t =


match t with Leaf -> Leaf
| Node ( h, l, r) ->
Node (f h, g l, g r)
end

module Tree = Mu(T)

Module List

module L =
struct
type (’a, ’b) t = Null
| Cons of ’a * ’b
let map (f, g) t =
match t with Null -> Null
| Cons ( hd, tl) ->
Cons (f hd, g tl)
end

module List = Mu(L)

21

You might also like