Showing posts with label Leibniz equality. Show all posts
Showing posts with label Leibniz equality. Show all posts

Friday, February 22, 2008

Name that type! (nested types edition)

If we want to write a type for binary trees in Haskell, it is easy to do so:


> data BinaryTree a = Leaf
>                   | InternalNode (BinaryTree a) a (BinaryTree a)

The structure of the type guarantees certain things about its inhabitants. For instance, every node has exactly two children. If we want to guarantee stronger invariants, we can change the shape of the type. We can write a a type for complete binary tree (that is, binary trees in which every leaf is at the same depth), as

> data CompleteBinaryTree a = Leaves
>                           | NonLeaves a (CompleteBinaryTree (a,a))

The argument in the recursive part of this datatype is not the same as it is in the declaration. Datatypes with this property are called nested or non-regular or heterogeneous or non-uniform. We can express all sorts of invariants with these datatypes. Here's another example:

> data AList a b = Nil
>                | Cons a (AList b a)

If we want to manipulate lists that alternate between two types a and b, we could use the type [Either a b], but this doesn't ensure that we don't have two as or two bs in a row. We could, instead, use the type [(a,b)], but this would only allow us to create lists of even length. By switching the position of the parameters in the recursion in AList, we can represent alternating lists of any length.

Here are some other examples of data structure invariants we can ensure with nested types:

Finally, here are 3.5 examples of nested types I haven't seen elsewhere. See if you can figure out what they do.

> data A x y = B (x y)
>            | C (A (D x) (x y))
> newtype D x y = D (y,x y)
> newtype K x = K x
> type QuestionOne = A K
>
> data E x = F x x
>          | G x (E x)
> data QuestionTwo x = Q2 (E (E x))
>
> data H x y = I
>            | J y x x (H (y,x) y)
> type L = H ()
> data QuestionThreePartA x = Q3a (L x) (L x) (L x)
> data QuestionThreePartB x = Q3b (L x) (QuestionThreePartA x)

Sunday, February 17, 2008

Leibniz and Liskov

Leibniz equality of two types a and b is the proposition that in any context, one can be substituted for the other:

f a -> f b
A value of this type brings to the value level the proof that two types are equal. The only value of this type is the identity function.

The Liskov substitution principle is very similar to Leibniz equality, but only in the contravariant position: If a function takes an argument of type b and a is a subtype of b, then the function must accept an argument of type a. If f is a type constructor that uses its argument only negatively, then a is a subtype of b if there is a value of type

f b -> f a
For example, λx . x -> b uses x negatively, and any b -> b is also trivially an a -> b when a is a subtype of b. The only value of type f b -> f a is the cast function.

Let's write the kind for type constructors that use their argument negatively as * -(-)-> * rather than just * -> *, and the kind for type constructors that use their argument positively as * -(+)-> *. Then, the following terms should validate our understanding that supertyping is dual to subtyping:

dual : ∀ a:* . ∀ b:* . ∀ g: * -(+)-> * . (∀ f: * -(-)-> * .  f b -> f a) -> g a -> g b
dual |a |b |g less bot = less [λx:* . g x -> g b] (λy:g b . y:g b) bot

dual' : ∀ a:* . ∀ b:* . ∀ f: * -(-)-> * . (∀ g: * -(+)-> * . g a -> g b) -> f b -> f a
dual' |a |b |f more top = more [λx:* . f x -> f a] (λy:f a . y:f a) top
So subtyping, like type equality, can be brought to the value domain. I now have two questions:
  1. Is there an analogue of FC (mirror) for F<: (mirror 1, mirror 2, mirror 3)?
  2. Is there a problem similar to decomposition for Liskov substitutability?

Wednesday, August 22, 2007

Leibniz Equality, Decomposition, and Definability

In any interesting logic, there are propositions which are true but not provable. The same goes for intuitionistic logic. By the Curry-Howard correspondence, there are types for which neither the types themselves nor their negations are inhabited in the typed lambda calculus. An example of this is Peirce's law: ∀ p, q . ((p -> q) -> p) -> p. We can use Heyting algebra to show that Peirce's law is not provable in intuitionistic logic. According to John C. Mitchell's Foundations for Programming Languages, problem 4.3.16, we could also show that this is not provable because:

. . . if there us a closed lambda term M:((a -> b) -> a) -> a then there is a closed normal form (the normal form of M) of this type. Show that this implicational formula is not provable by showing there is no closed normal form term of this type.

In Emir Pasalic's PhD thesis, (end of section 4.2.2, page 80 in the PDF, 70 in print), he mentions that it is unknown whether the following type is inhabited:

∀ a, b, c, d . Equal (a,b) (c,d) -> Equal a c
where type equality is defined by Leibniz equality
data Equal a b = Equal (∀ f . f a -> f b)
To avoid dealing with datatypes or pairs, this can be expanded to
∀ a, b, c, d . 
    (∀ f . f (∀ r . (a -> b -> r) -> r) -> f (∀ s . (c -> d -> s) -> s)) 
    ->
    (∀ g . g a -> g c)
In GADTless Programming in Haskell 98 (Section 6, top of page 13) Martin Sulzmann and Meng Wang call this the decomposition law.

Is there some Heyting algebra for higher-order polymorphic typed lambda calculi that we can use to show that this type is uninhabited?