language-pts-0: Pure Type Systems

Safe HaskellNone
LanguageHaskell2010

Language.PTS.Examples.Identity

Description

Identity function is used often to demonstrate polymorphic calculus. This is not an exception.

Synopsis

Documentation

stlcUnitIdentity :: Term STLC Source #

In simple typed lambda calculus one have to define separate functions for different types, even they have same shape.

>>> demo_ basicCtx stlcUnitIdentity
λ x → x : Unit → Unit ↪ λ x → x : Unit → Unit

demo_ prints the term, result of evaluation and checked type

term ↪ value : type

stlcBoolIdentity :: Term STLC Source #

Next we can write identity function for booleans:

>>> demo_ basicCtx stlcBoolIdentity
λ x → x : Bool → Bool ↪ λ x → x : Bool → Bool

If we would write the type-inferencer for STLC (TODO), it would need to default types for such intristically polymorphic values.

As this is the first example, let's see evaluator and type-checker in action:

>>> demo_ basicCtx ("True" :: Term STLC)
True ↪ True : Bool

Next we apply True to the identity function:

>>> demo_ basicCtx $ stlcBoolIdentity @@ "True"
(λ x → x : Bool → Bool) True ↪ True : Bool

If we apply the value of wrong type, we get an error:

>>> demo_ basicCtx $ stlcBoolIdentity @@ "TT"
error:
• Couldn't match expected type Bool with actual type Unit
• In the expression: TT
• when checking expression
  (λ x → x : Bool → Bool) TT

Because the library is based on PTS, we could try to apply a type too, but that's also a type-error:

>>> demo_ basicCtx $ stlcBoolIdentity @@ "Bool"
error:
• Couldn't match expected type Bool with actual type ⋆
• In the expression: Bool
• when checking expression
  (λ x → x : Bool → Bool) Bool

polymorphicIdentity :: Specification s => Term s Source #

Because simply typed lambda calculus is restrictive, we have polymorphic calculi.

In language-pts we can define the term once and for all specications.

systemfIdentity :: Term SystemF Source #

However let's experiment with SystemF first.

>>> demo_ emptyCtx systemfIdentity
λ a x → x : ∀ a → a → a ↪ λ a x → x : ∀ a → a → a

Note: emptyCtx. We can apply values. When we apply a Bool we get boolean identity function, and further we can apply a Value

>>> demo_ basicCtx $ systemfIdentity @@ "Bool"
(λ a x → x : ∀ a → a → a) Bool ↪ λ x → x : Bool → Bool
>>> demo_ basicCtx $ systemfIdentity @@ "Bool" @@ "False"
(λ a x → x : ∀ a → a → a) Bool False ↪ False : Bool

As with STLC, we get type-error if we apply value of wrong type:

>>> demo_ basicCtx $ systemfIdentity @@ "Unit" @@ "False"
error:
• Couldn't match expected type Unit with actual type Bool
• In the expression: False
• when checking expression
  (λ a x → x : ∀ a → a → a) Unit False

And "sort" error, if we try to apply value directly!

>>> demo_ basicCtx $ systemfIdentity @@ "False"
error:
• Couldn't match expected type ⋆ with actual type Bool
• In the expression: False
• when checking expression
  (λ a x → x : ∀ a → a → a) False

stlcIdentity :: Term STLC Source #

Note: we can write polymorphic looking identity function in PTS for STLC, but it won't typecheck:

>>> demo_ emptyCtx stlcIdentity
error:
• No PTS Rule (□,⋆,-)
• when checking expression
  λ a x → x : ∀ a → a → a

hindleyMilnerIdentity :: Term HindleyMilner Source #

In Haskell we can apply identity function to itself

>>> :t id id
id id :: a -> a

GHCs "type-checker" (actually inferrer) infers the following value. Note that all applied types are simple, monomorphic types (no forall_):

>>> demo_ emptyCtx $ lam_ "b" (systemfIdentity @@ ("b" ~> "b") @@ (systemfIdentity @@ "b")) -:- forall_ "b" ("b" ~> "b")
λ b → (λ a x → x : ∀ a → a → a)
          (b → b) ((λ a x → x : ∀ a → a → a) b)
    : ∀ b → b → b
    ↪ λ b x → x : ∀ b → b → b

Alternatively, different value can be inferred (AFAIK that's what Agda would do). Here, as we don't abstract (lam_), we don't need annotations, due bi-directional type-checking in language-pts!

>>> demo_ emptyCtx $ systemfIdentity @@ forall_ "b" ("b" ~> "b") @@@ systemfIdentity
(λ a x → x : ∀ a → a → a)
    (∀ b → b → b) (λ a x → x : ∀ a → a → a)
    ↪ λ a x → x : ∀ b → b → b

But this won't type-check in predicative System F (= Hindley-Milner, HindleyMilner) system:

>>> demo_ emptyCtx $ hindleyMilnerIdentity @@ forall_ "b" ("b" ~> "b") @@@ hindleyMilnerIdentity
error:
• Couldn't match expected type M with actual type P
• In the expression: ∀ b → b → b
• when checking expression
  (λ a x → x : ∀ a → a → a) (∀ b → b → b)
  (λ a x → x : ∀ a → a → a) (∀ b → b → b) (λ a x → x : ∀ a → a → a)

Former is however, ok. Note that we get a polymorphic value!

>>> demo_ emptyCtx $ Ann (lam_ "b" (hindleyMilnerIdentity @@ ("b" ~> "b") @@ (hindleyMilnerIdentity @@ "b"))) (forall_ "b" ("b" ~> "b"))
λ b → (λ a x → x : ∀ a → a → a)
          (b → b) ((λ a x → x : ∀ a → a → a) b)
    : ∀ b → b → b
    ↪ λ b x → x : ∀ b → b → b