true ≡ Λα. λy:α. λn:α. y
false ≡ Λα. λy:α. λn:α. n
not ≡ λp:Bool. p [Bool] false true
- and ≡ λp:Bool. λq:Bool. p [Bool] (q [Bool]) false
- or ≡ λp:Bool. λq:Bool. p [Bool] true (q [Bool])
+ and ≡ λp:Bool. λq:Bool. p [Bool] q false
+ or ≡ λp:Bool. λq:Bool. p [Bool] true q
+
+ When I first wrote up these answers, I had put `(q [Bool])` where I now have just `q` in the body of `and` and `or`. On reflection,
+ this isn't necessary, because `q` is already a `Bool`. But as I learned by checking these answers with Pierce's evaluator, it's
+ also a mistake. What we want is a result whose type _is_ `Bool`, that is, `∀α. α -> α -> α`. `(q [Bool])` doesn't have that type, but
+ rather the type `Bool -> Bool -> Bool`. The first, desired, type has an outermost `∀`. The second, wrong type doesn't; it only has `∀`s
+ inside the antecedents and consequents of the various arrows. The last one of those could be promoted to be an outermost `∀`, since
+ `P -> ∀α. Q ≡ ∀α. P -> Q` when `α` is not free in `P`. But that couldn't be done with the others.
The type `Nat` (for "natural number") may be encoded as follows:
-- Or this:
let sysf_true = (\y n -> y) :: Sysf_bool a
- :set -XExplicitForAll
+ Note that in both OCaml and Haskell code, the generalization `∀α` on the free type variable `α` is implicit. If you really want to, you can supply it explicitly in Haskell by saying:
+
+ :set -XExplicitForAll
let { sysf_true :: forall a. Sysf_bool a; ... }
-- or
let { sysf_true :: forall a. a -> a -> a; ... }