Expressing normal data types such as lists and nats is straightforward and there are many examples around. What is the generic procedure to translate GADTs, though? Some examples translating typical types such as Vector and dependent products from Idris to Morte would be very illustrative.
You can't get eliminators that depend on elements of data types, but you can define eliminators that depend on indices of elements of data types. Hence, Vectors are representable (the code is in Agda):
Nat = (P : Set) -> (P -> P) -> P -> P
zero : Nat
zero = λ P f z -> z
suc : Nat -> Nat
suc = λ n P f z -> f (n P f z)
plus : Nat -> Nat -> Nat
plus = λ n m P f z -> n P f (m P f z)
Vec = λ (A : Set) (n : Nat) ->
(P : Nat -> Set) -> (∀ n -> A -> P n -> P (suc n)) -> P zero -> P n
nil : ∀ A -> Vec A zero
nil = λ A P f z -> z
cons : ∀ A n -> A -> Vec A n -> Vec A (suc n)
cons = λ A n x xs P f z -> f n x (xs P f z)
concat : ∀ A n m -> Vec A n -> Vec A m -> Vec A (plus n m)
concat = λ A n m xs ys P f z -> xs (λ n -> P (plus n m)) (λ n -> f (plus n m)) (ys P f z)
These are very similar to Church-encoded lists, you just make a type, that you eliminate into, dependent on the indices of a data type being defined and change induction hypotheses to reflect the structure of the constructors of the data type. I.e. you have
cons : ∀ A n -> A -> Vec A n -> Vec A (suc n)
so the corresponding induction hypothesis is
∀ n -> A -> P n -> P (suc n)
In order to define dependent pairs without inductive types, you need very/insanely dependent types (sigmas are here), which allow the result of a function depend on this same function being defined. Morte doesn't have this, of course.
Everything that is representable is documented in the Morte tutorial. GADTs and (more generally) indexed types aren't there, and indeed they aren't possible.
(EDIT: GADTs can be in fact represented; see other answer by user3237465)
The Vector type itself can be encoded, but its values aren't usable for much. A Vector n A is an n-nested pair of A-s:
Unit = \(A : *) -> A -> A
Pair = \(A B : *) -> (P : *) -> (A -> B -> P) -> P
Nat = (N : *) -> (N -> N) -> N -> N
Vector = \(n : Nat)(A : *) -> n * (\(t : *) -> Pair A t) Unit
But writing any useful function for Vector n A would require induction on its n length, but Morte has no inductive types.
To be clear, by induction I mean that for a certain type a function corresponding to the principle of structural induction is derivable. These are generalizations of folds where the output type may depend on the input value. For some natural number type Nat : * with suc : Nat -> Nat and zero : Nat induction has the following type:
natInd :
(N : Nat -> *) -- a predicate,
-> ((n : Nat) -> N n -> N (suc n)) -- if it's preserved by suc
-> N zero -- and holds for zero,
-> (n : Nat) -> N n -- holds for every Nat
While folding over a Vector, the type changes along with the length (since the former depends on the latter). However, with Church Nat we only have non-dependent fold (aka "recursion") instead of possibly type-changing fold (aka "induction").
Yes. As an example, this answer shows how to write the Refl type.
Let's say we want to build a simple DSL. Here's how to do ti:
Expr t = forall (E :: * -> *). forall
(IntLit :: Integer -> E Integer),
(IntVar :: Char -> E Integer),
(Add :: E Integer -> E Integer -> E Integer),
(Mult :: E Integer -> E Integer -> E Integer),
(Neg :: E Integer -> E Integer),
(IntEq :: E Integer -> E Integer -> E Bool),
(Lt :: E Integer -> E Integer -> E Bool),
(And :: E Bool -> E Bool -> E Bool),
(Or :: E Bool -> E Bool -> E Bool),
(Not :: E Bool -> E Bool),
(If :: (forall x :: *. E Bool -> E x -> E x -> E x)).
E t
Related
In Haskell, if one enables the RankNTypes extension
{-# Language RankNTypes #-}
then one can define the natural numbers as they are encoded in System-F:
type Nat = forall a. a -> ((a -> a) -> a)
zero :: Nat
zero = \z s -> z
succ :: Nat -> Nat
succ n = \z s -> s (n z s)
fold :: a -> (a -> a) -> Nat -> a
fold z s n = n z s
Yay! The next step is to define the case operation: the idea is that
caseN :: Nat -> a -> (Nat -> a) -> a
caseN n z f = "case n of
zero -> z
succ m -> f m"
Of course that's not directly possible. One thing that is possible is to define the natural numbers as normally {data Nats = Zero | Succ Nats} and define "conversions" between Nat and Nats, and then use the syntactic case construct built-in to Haskell.
In the untyped lambda calculus, caseN can be written as
caseN n b f = snd (fold (zero, b) (\(n0, _) -> (succ n0, f n0)) n)
following a trick apparently discovered by Kleene for defining the predecessor function. This version of caseN does look like it should typecheck with the type given above. (zero, b) :: (Nat, b) and \(n0, _) -> (succ n0, f n0) :: (Nat, b) -> (Nat, b), so fold (zero, b) (\(n0, _) -> (succ n0, f n0)) n :: (Nat, b).
However this doesn't typecheck in Haskell. Trying to isolate the inner function \(n0, _) -> (succ n0, f n0) with
succf :: (Nat -> b) -> (Nat, b) -> (Nat, b)
succf f (n, _y) = (succ n, f n)
reveals that the ImpredicativeTypes extension may be needed, as succf seems to require that extension. For the more typical {data Nats = Zero | Succ Nats}, the caseN construct does work (after changing to the appropriate fold, and Zero, Succ).
Is it possible to get caseN to work on Nat directly? Is a different trick needed?
I think the typical trick is to use a data type (or newtype, as pointed out by a commenter) wrapper. To start, instead of defining Nat as a type synonym, you can define it as:
newtype Nat = Nat { unNat :: forall a. a -> ((a -> a) -> a) }
This is isomorphic to your definition, except that you must explicitly wrap and unwrap the contents.
We can continue by writing the same definitions you had:
zero :: Nat
zero = Nat $ \z s -> z
succ :: Nat -> Nat
succ (Nat n) = Nat $ \z s -> s (n z s)
fold :: a -> (a -> a) -> Nat -> a
fold z s (Nat n) = n z s
This is basically what you already had, but now with explicit wrapping and unwrapping using Nat (as both constructor and pattern).
At this point, your final definitions just work:
caseN :: Nat -> b -> (Nat -> b) -> b
caseN n b f = snd (fold (zero,b) (\(n0,_) -> (succ n0,f n0)) n)
succf :: (Nat -> b) -> (Nat, b) -> (Nat, b)
succf f (n,_y) = (succ n, f n)
Asking the GHC to print the type of "one" and "succ zero" (lambda calculus way of encoding numerals), I get two different types!
Shouldn't they be the same?
Can you also show me how to derive its type manually?
zero = \ f x -> x
one = \ f x -> f x
succ = \ n f x -> f (n (f x))
:t one -- (t1 -> t2) -> t1 -> t2
:t succ zero -- ((t1 -> t1) -> t2) -> (t1 -> t1) -> t2
So as was said in the comments, the correct definition is
zero f x = x
succ n f x = f (n f x)
"do one more f after n applications of f, starting with x."
Thus
one f x = succ zero f x = f (zero f x) = f x
two f x = succ one f x = f (one f x) = f (f x)
The types which get derived are more general initially,
zero :: t -> t1 -> t1 -- most general
one :: (t1 -> t ) -> t1 -> t -- less general
succ one :: (t2 -> t2) -> t2 -> t2 -- most specific
but it doesn't matter, they all match (unify) between themselves, and starting from two = succ one the type settles down into the most specific (b -> b) -> (b -> b).
You could also define
church :: Int -> (b -> b) -> b -> b -- is derived so by GHCi
church n f x = foldr ($) x (replicate n f)
= foldr (.) id (replicate n f) x
{- church n = foldr (.) id . replicate n -- (^ n) for functions -}
and have all types be exactly the same, as
church 0 :: (b -> b) -> b -> b
church 1 :: (b -> b) -> b -> b
church 2 :: (b -> b) -> b -> b
It really doesn't matter.
As to the type derivations, it comes down to just using the modus ponens / application rule,
f :: a -> b
x :: a
-------------
f x :: b
Just need to be careful renaming each type consistently so there's no type variable capture introduced at any step:
succ n f x = f (n f x)
x :: a
f :: t , t ~ ...
n :: t -> a -> b
f :: b -> c , t ~ b -> c
succ n f x :: c
succ :: (t -> a -> b) -> (b -> c) -> a -> c
:: ((b -> c) -> a -> b) -> (b -> c) -> a -> c
(because final result type produced by succ is the same as the final result type produced by f -- i.e. c), or as GHCi puts it,
succ :: ((t1 -> t) -> t2 -> t1) -> (t1 -> t) -> t2 -> t
-- b c a b b c a c
Firstly, you want zero to be same type as one. In your equation for zero, you don't use f on rhs of ->. So the compiler doesn't know what type to infer. In your equation for one, you want f x (its result) to be same type as x (the result from zero). But you're not getting that either. It's easiest to give signatures, but failing that use asTypeOf.
In the equation for succ, you want its result to be same type as f x, same type as x.
Can you also show me how to derive its type manually?
OK let's achieve the above using asTypeOf. Then you can use :t to find the types ...
zero = \ f x -> (x `asTypeOf` f x)
one = \ f x -> (f x `asTypeOf` x)
succ = \ n f x -> (f (n f x)
`asTypeOf` f x `asTypeOf` x)
(I've used the correct definition for succ, per #LambdaFairy.)
Note that Church numerals are framed in the untyped lambda calculus -- that's what wikipedia is showing. As you get into more exotic functions over them (like addition or predecessor), you'll find that Haskell is a typed lambda calculus, and GHC will barf/you'll hit the dreaded monomorphism restriction. Then asTypeOf can't help you; you must resort to type signatures (of higher-rank).
data Nat = Zero | Succ Nat
type Predicate = (Nat -> Bool)
-- forAllNat p = (p n) for every finite defined n :: Nat
implies :: Bool -> Bool -> Bool
implies p q = (not p) || q
basecase :: Predicate -> Bool
basecase p = p Zero
jump :: Predicate -> Predicate
jump p n = implies (p n) (p (Succ n))
indstep :: Predicate -> Bool
indstep p = forallnat (jump p)
Question:
Prove that if basecase p and indstep p, then forAllNat p
What I do not understand is that if basecase p and indstep p, so forAllNat p should be True, of course.
I think basecase p says that P(0) is true, and
indstep p says that P(Succ n) which is P(n+1) is true
And we need to prove P(n) is true.
Am I right?
Any suggestion about how to do this?
As Benjamin Hodgson indicates, you can't quite prove that in Haskell. However, you can prove a statement with slightly stronger preconditions. I'll also ignore the unnecessary complexity of Bool.
{-# LANGUAGE GADTs, KindSignatures, DataKinds, RankNTypes, ScopedTypeVariables #-}
data Nat = Z | S Nat
data Natty :: Nat -> * where
Zy :: Natty 'Z
Sy :: Natty n -> Natty ('S n)
type Base (p :: Nat -> *) = p 'Z
type Step (p :: Nat -> *) = forall (n :: Nat) . p n -> p ('S n)
induction :: forall (p :: Nat -> *) (n :: Nat) .
Base p -> Step p -> Natty n -> p n
induction b _ Zy = b
induction b s (Sy n) = s (induction b s n)
You can't prove this within Haskell. (Turns out you can.) The language is not dependently typed enough. It's a programming language, not a proof assistant. I think the assignment probably expects you to prove it on pencil and paper.
You can do it in Agda though.
data Nat : Set where
zero : Nat
suc : Nat -> Nat
Pred : Set -> Set1
Pred A = A -> Set
Universal : {A : Set} -> Pred A -> Set
Universal {A} P = (x : A) -> P x
Base : Pred Nat -> Set
Base P = P zero
Step : Pred Nat -> Set
Step P = (n : Nat) -> P n -> P (suc n)
induction-principle : (P : Pred Nat) -> Base P -> Step P -> Universal P
induction-principle P b s zero = b
induction-principle P b s (suc n) = s n (induction-principle P b s n)
(You may recognise induction-principle as being Nat's foldr.)
You may be able to get something a bit like this when TypeInType lands in GHC 8. It won't be pretty though.
I have a type level numbers
data Z deriving Typeable
data S n deriving Typeable
and n-ary functions (code from fixed-vector package)
-- | Type family for n-ary functions.
type family Fn n a b
type instance Fn Z a b = b
type instance Fn (S n) a b = a -> Fn n a b
-- | Newtype wrapper which is used to make 'Fn' injective. It's also a
-- reader monad.
newtype Fun n a b = Fun { unFun :: Fn n a b }
I need function like
uncurryN :: Fun (n + k) a b -> Fun n a (Fun k a b)
I read several articles about type level computations, but all about type safe list concatenation.
This required a bit of care in unwrapping/rewrapping the Fun newtype. I also exploited the DataKinds extension.
{-# LANGUAGE DataKinds, KindSignatures, TypeFamilies,
MultiParamTypeClasses, ScopedTypeVariables, FlexibleInstances #-}
{-# OPTIONS -Wall #-}
-- | Type-level naturals.
data Nat = Z | S Nat
-- | Type family for n-ary functions.
type family Fn (n :: Nat) a b
type instance Fn Z a b = b
type instance Fn (S n) a b = a -> Fn n a b
-- | Addition.
type family Add (n :: Nat) (m :: Nat) :: Nat
type instance Add Z m = m
type instance Add (S n) m = S (Add n m)
-- | Newtype wrapper which is used to make 'Fn' injective.
newtype Fun n a b = Fun { unFun :: Fn n a b }
class UncurryN (n :: Nat) (m :: Nat) a b where
uncurryN :: Fun (Add n m) a b -> Fun n a (Fun m a b)
instance UncurryN Z m a b where
uncurryN g = Fun g
instance UncurryN n m a b => UncurryN (S n) m a b where
uncurryN g = Fun (\x -> unFun (uncurryN (Fun (unFun g x)) :: Fun n a (Fun m a b)))
{- An expanded equivalent with more signatures:
instance UncurryN n m a b => UncurryN (S n) m a b where
uncurryN g = let f :: a -> Fn n a (Fun m a b)
f x = let h :: Fun (Add n m) a b
h = Fun ((unFun g :: Fn (Add (S n) m) a b) x)
in unFun (uncurryN h :: Fun n a (Fun m a b))
in Fun f
-}
You can do this without any type classes by constructing a datatype which can represent the type Nat on the data level:
data Nat = Z | S Nat
type family Fn (n :: Nat) a b
type instance Fn Z a b = b
type instance Fn (S n) a b = a -> Fn n a b
type family Add (n :: Nat) (m :: Nat) :: Nat
type instance Add Z m = m
type instance Add (S n) m = S (Add n m)
newtype Fun n a b = Fun { unFun :: Fn n a b }
data SNat (n :: Nat) where
SZ :: SNat Z
SS :: SNat n -> SNat (S n)
uncurryN :: forall n m a b . SNat n -> Fun (Add n m) a b -> Fun n a (Fun m a b)
uncurryN SZ f = Fun f
uncurryN (SS (n :: SNat n')) g = Fun (\x -> unFun (uncurryN n (Fun (unFun g x)) :: Fun n' a (Fun m a b)))
If you don't like explicitly mentioning the n parameter, thats ok since you can always go back and forth between a function which takes an parameter as a type class and which takes a parameter as data:
class SingI (a :: k) where
type Sing :: k -> *
sing :: Sing a
instance SingI Z where
type Sing = SNat
sing = SZ
instance SingI n => SingI (S n) where
type Sing = SNat
sing = SS sing
toNatSing :: (SNat n -> t) -> (SingI n => t)
toNatSing f = f sing
fromNatSing :: (SingI n => t) -> (SNat n -> t)
fromNatSing f SZ = f
fromNatSing f (SS n) = fromNatSing f n
uncurryN' :: SingI n => Fun (Add n m) a b -> Fun n a (Fun m a b)
uncurryN' = toNatSing uncurryN
In Haskell, it is easy to write functions that act on or return tuples of things, e.g. the prelude function splitAt:
splitAt :: Int -> [a] -> ([a], [a])
but is there no easy, convenient, way of writing functions that act on or result in cotuples of things? E.g. a function that returns an Int or a Double. As a concrete example, let's say I want to write a function
MyDivision :: Int -> Int -> (Int + Double)
where + is my symbol for cotupling, so MyDivision x y returns x/y as an Int if the division results in an integer but as a Double if the division does not result in an integer.
So far, it seems that I have two choices, either declare a new datatype
data IntOrDouble = AnInt Int | ADouble Double
or use
Either Int Double
where the first alternative requires a lot of typing and thinking of names and the second alternative quickly gets messy when you have larger cotuples and get types looking like
Either (Either a (Either b c)) (Either (Either d f) g)
Now, if I had a a cotuple type, say
a + b + c + d
I would like to be able to form functions
f :: (a + b + c + d) -> e
g :: (a + b + c + d) -> (e + f + g + h)
by just supplying functions
f1 :: a -> e, f2 :: b -> e, f3 :: c -> e, f4 :: d -> e
g1 :: a -> e, g2 :: b -> f, g3 :: c -> g, g4 :: d -> h
and setting
f = f1 + f2 + f3 + f4
g = g1 <+> g2 <+> g3 <+> g4
or something of the like.
Is this possible?
Well co-tuples are properly called coproducts which is just Either.
So, let's go ahead and do something like
{-# LANGUAGE TypeOperators #-}
type (+) = Either
This is left associative by the way. Now we have pretty syntax like
foo :: Int + Bool + Char
foo = Right 'c'
Now, what you seem to want there is in fact very similar to a church representation of Either flattened out. We can just build this up with the either combinator
(+) :: (a -> c) -> (b -> c) -> (a + b) -> c
l + r = either l r
(<+>) :: (a -> c) -> (b -> d) -> (a + b) -> (c + d)
l <+> r = either (Left . l) (Right . r)
infixl 4 <+>, +
A fun challenge would be to create a generic inject function which takes something like Proxy k where k is some representation of natural numbers at the type level and returns a great nested mess of Eithers for you.
Update:
I got bored, here's the code for generic inj
data Nat = S Nat | Z
type NatRep (n :: Nat) = Proxy n
type family Tuplish (l :: Nat) (r :: Nat) t
type instance Tuplish Z Z t = t
type instance Tuplish (S n) Z t = (Tuplish n Z ()) + t
type instance Tuplish l (S n) t = (Tuplish l n t) + ()
predP :: Proxy (S n) -> Proxy n
predP = reproxy
class Inject (l :: Nat) (r :: Nat) v where
inj :: NatRep l -> NatRep r -> v -> Tuplish l r v
instance Inject Z Z v where
inj _ _ = id
instance Inject (S n) Z v where
inj _ _ v = Right v
instance Inject n m v => Inject n (S m) v where
inj l r v = Left (inj l (predP r) v)
I renamed your + to >+< and your <+> to >*<, but you could do something like this:
type a + b = Either a b
(>+<) :: (a -> c) -> (b -> c) -> a + b -> c
(>+<) = either
(>*<) :: (a -> e) -> (b -> f) -> a + b -> e + f
(f >*< _) (Left a) = Left (f a)
(_ >*< g) (Right b) = Right (g b)
I tried to name the operators to be more suggestive of their operation.
Here's another way to implement >*<:
import Control.Arrow ((+++))
(>*<) :: (a -> e) -> (b -> f) -> a + b -> e + f
(>*<) = (+++)
As a side note: "Tuples" are often called product types and this is what's called a coproduct type (or sum type). The most basic coproduct type is Either and all other coproduct types are isomorphic to Either A B for some types A and B.