I'm trying to study church numerals in Haskell by giving the numbers a type like this, with the idea that a natural number n
is basically the expression that applies the function in the following type to the value of type t
for n
times.
type Nat = forall t. (t -> t) -> t -> t
With that idea, I can define zero
, successor
, plus
, mult
in the following ways:
zero :: Nat
zero = \f t -> t
succ :: Nat -> Nat
succ n = \f -> f . (n f)
plus :: Nat -> Nat -> Nat
plus m n = \f -> (m f) . (n f)
mult :: Nat -> Nat -> Nat
mult m n = \f -> m (n f) -- Equal to \f -> (m . n) f
-- Pointfree version
mult' :: Nat -> Nat -> Nat
mult' = (.)
When I try to define exponentiation, I'd like to try applying the same reasoning that allowed me to define multiplication, namely applying mult m
n
times to 1
.
This leads to the following code
exp' :: Nat -> Nat -> Nat
exp' m n = n (mult m) (succ zero)
But this does type check with the following error from GHC:
Couldn't match type ‘t’ with ‘t1’
‘t’ is a rigid type variable bound by
the type signature for:
exp' :: forall t. Nat -> Nat -> (t -> t) -> t -> t
at church.lhs:44:3
‘t1’ is a rigid type variable bound by
a type expected by the context:
forall t1. (t1 -> t1) -> t1 -> t1
at church.lhs:44:17
Expected type: ((t -> t) -> t -> t) -> (t -> t) -> t -> t
Actual type: Nat -> Nat
The error seems to say that the typechecker is not instantiating the type for n
properly, ideally type t
should be instantiated with another (t -> t
) for the expression to go through.
What's also confusing me is that the following code typechecks:
exp :: Nat -> Nat -> Nat
exp m n = n ((.) m) (succ zero) -- replace mult by (.)
Would someone mind explaining what's the problem here? Why does the first definition of exp'
not typecheck but the second exp
typecheks?
Thanks!