Problem with types in a definition in lean - lean

If I make the definition
definition f (x : nat) := λ m, x + m
then #check f returns f:nat -> nat -> nat, as expected.
If instead I try to define
definition f (x : nat) : nat -> nat -> nat := λ m, x + m
then Lean complains, and that x has type nat but is expected to have type nat -> nat.
Why is this?

There are basically three ways of defining f
def f (x m : nat) : nat := x + m
def f (x : nat) : nat -> nat := λ m, x + m
def f : nat -> nat -> nat := λ x m, x + m
The type of all three of these fs is the same, there is simply different syntax for defining the function. Everything to the left of the colon is an input to the function, and after the colon is the return type. The term right of the := should have the type after the colon. In your second example, the type of the term after the := is nat -> nat, but the expected type is nat -> nat -> nat, because that's what was written after the colon. So there was an error.
All of the arguments left of the colon are included in the type of f if you type #check f.

Related

How to represent arbitrary GADTs on Morte?

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

RankNTypes and Church numerals

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!
The reason that it doesn't work is it involves several impredicative instantiations, which isn't even normally allowed in Haskell. If you turn on -XImpredicativeTypes, you can get it to compile:
{-# LANGUAGE ImpredicativeTypes #-}
...
exp' :: Nat -> Nat -> Nat
exp' m n = n (mult m) (succ zero)
The second version typechecks because mult' has a higher rank type, even though it is definitionally equal to (.), so typechecking proceeds differently. Since the type of (.) is simpler (rank 1) typechecking will succeed more often.
The GHC docs warn ImpredicativeTypes does not work so I would caution against using it. The typical way to get around this it to simple use a newtype:
newtype Nat' = N { instN :: Nat }
exp'' :: Nat -> Nat -> Nat
exp'' m n = instN $ n (\(N q) -> N $ mult m q) (N $ succC zero)
To see the impredicative instantiation in action, you can use typed holes:
exp' :: Nat -> Nat -> Nat
exp' m n = _ (mult m) (succC zero)
This will report the type forall a . (Nat -> Nat) -> Nat -> (a -> a) -> a -> a, which is the same as (Nat -> Nat) -> Nat -> Nat. Since you place n there, you have to unify this type with forall a . (a -> a) -> a -> a, which involves instantiating the type variable a with the polytype Nat.

How to implement mathematics induction on Haskell

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.

Is it possible to write fmap for this data type involving a type family?

Given the following type family (supposed to reflect the isomorphism A×1 ≅ A)
type family P (x :: *) (a :: *) :: * where
P x () = x
P x a = (x, a)
and data type defined in terms thereof
data T a = T Integer (P (T a) a)
is it possible by some type hackery to write a Functor instance for the latter?
instance Functor T where
fmap f = undefined -- ??
Intuitively, it's obvious what to do depending on the type of f, but I don't know how to express it in Haskell.
I tend to reason about these kind higher kind programs using Agda.
The problem here is that you want to pattern match on * (Set in Agda), violate parametericity, as mentioned in the comment. That is not good, so you cannot just do it. You have to provide witness. I.e. following is not possible
P : Set → Set → Set
P Unit b = b
P a b = a × b
You can overcome the limitiation by using aux type:
P : Aux → Set → Set
P auxunit b = b
P (auxpair a) b = a × b
Or in Haskell:
data Aux x a = AuxUnit x | AuxPair x a
type family P (x :: Aux * *) :: * where
P (AuxUnit x) = x
P (AuxPair x a) = (x, a)
But doing so you'll have problems expressing T, as you need to pattern match on its parameter again, to select right Aux constructor.
"Simple" solution, is to express T a ~ Integer when a ~ (), and T a ~ (Integer, a) directly:
module fmap where
record Unit : Set where
constructor tt
data ⊥ : Set where
data Nat : Set where
zero : Nat
suc : Nat → Nat
data _≡_ {ℓ} {a : Set ℓ} : a → a → Set ℓ where
refl : {x : a} → x ≡ x
¬_ : ∀ {ℓ} → Set ℓ → Set ℓ
¬ x = x → ⊥
-- GADTs
data T : Set → Set1 where
tunit : Nat → T Unit
tpair : (a : Set) → ¬ (a ≡ Unit) → a → T a
test : T Unit → Nat
test (tunit x) = x
test (tpair .Unit contra _) with contra refl
test (tpair .Unit contra x) | ()
You can try to encode this in Haskell to.
You can express it using e.g. 'idiomatic' Haskell type inequality
I'll leave the Haskell version as an exercise :)
Hmm or did you meant by data T a = T Integer (P (T a) a):
T () ~ Integer × (P (T ()) ())
~ Integer × (T ())
~ Integer × Integer × ... -- infinite list of integers?
-- a /= ()
T a ~ Integer × (P (T a) a)
~ Integer × (T a × a) ~ Integer × T a × a
~ Integer × Integer × ... × a × a
Those are easier to encode directly as well.

How to work with higher rank types

Playing with the church numerals. I run into the situation I can't guide the GHC type-checker around higher order types.
First I wrote an version, without any type signatures:
module ChurchStripped where
zero z _ = z
inc n z s = s (n z s)
natInteger n = n 0 (1+)
add a b = a b inc
{-
*ChurchStripped> natInteger $ add (inc $ inc zero) (inc $ inc $ inc zero)
5
-}
mult a b = a zero (add b)
{-
*ChurchStripped> natInteger $ mult (inc $ inc zero) (inc $ inc $ inc zero)
6
-}
The inferred type of mult is horrible, so I tried to clean-up the types with a type definitions:
module Church where
type Nat a = a -> (a -> a) -> a
zero :: Nat a
zero z _ = z
inc :: Nat a -> Nat a
inc n z s = s (n z s)
natInteger :: Nat Integer -> Integer
natInteger n = n 0 (1+)
{- `add :: Nat a -> Nat a -> Nat a` doesn't work, and working signature looks already suspicious -}
add :: Nat (Nat a) -> Nat a -> Nat a
add a b = a b inc
{-
*Church> natInteger $ add (inc $ inc zero) (inc $ inc $ inc zero)
5
-}
mult :: Nat (Nat a) -> Nat (Nat a) -> Nat a
mult a b = a zero (add b)
{-
*Church> natInteger $ mult (inc $ inc zero) (inc $ inc $ inc zero)
6
-}
It works, but the types aren't as clean as they could be. Following the System F definitions I tried:
{-# LANGUAGE RankNTypes #-}
module SystemF where
type Nat = forall a. a -> (a -> a) -> a
zero :: Nat
zero z _ = z
inc :: Nat -> Nat
inc n z s = s (n z s)
natInteger :: Nat -> Integer
natInteger n = n 0 (1+)
{- This doesn't work anymore
add :: Nat -> Nat -> Nat
add a b = a b inc
Couldn't match type `forall a1. a1 -> (a1 -> a1) -> a1'
with `a -> (a -> a) -> a'
Expected type: (a -> (a -> a) -> a) -> a -> (a -> a) -> a
Actual type: Nat -> a -> (a -> a) -> a
In the second argument of `a', namely `inc'
In the expression: a b inc
In an equation for `add': add a b = a b inc
-}
I guess it should be possible to write add with Nat -> Nat -> Nat type signature, but I have no idea how.
P.S. actually I started from the bottom, but it maybe easier to present this problem this way.
bennofs is right, you really want to help the typechecker along here, in particular in add where you need to instantiate the a in forall a . a -> (a -> a) -> a with Nat (ie, the same forall a . ... type).
One way to do that is to introduce a newtype that wraps the polymorphic type:
newtype Nat' = N Nat
Now you can go between Nat and Nat' via N, and back using unN
unN :: Nat' -> Nat
unN (N n) = n
(It's worth noting at this point that newtype Nat' = N Nat is a different beast from data Nat2 = forall a . N2 (a -> (a -> a) -> a). The latter requires -XExistentialQuantification because it says that for some particular choice of a, you can make a Nat2. On the other hand, the former still says that if you have a -> (a -> a) -> a for any arbitrary a, then you can make a Nat'. For Nat' you need -XRankNTypes, but you don't need existentials.)
Now we can also make inc' to increment a Nat':
inc' :: Nat' -> Nat'
inc' (N n) = N (inc n)
And we're ready to add:
add :: Nat -> Nat -> Nat
add n m = unN (n (N m) inc')
The reason this works is because now instead of trying to convince GHC to instantiate the type of n with a polymorphic type ∀ a . a -> (a -> a) -> a on its own, the N acts as a hint.
Example:
> natInteger (add (inc zero) (inc zero))
2
I don't understand RankNTypes well enough to tell why your original example doesn't work, but if you pack Nat into a data type, then it works:
{-# LANGUAGE RankNTypes #-}
module SystemF where
data Nat = Nat (forall a. (a -> (a -> a) -> a))
zero :: Nat
zero = Nat const
inc :: Nat -> Nat
inc (Nat n) = Nat $ \z s -> s $ n z s
natInteger :: Nat -> Integer
natInteger (Nat n) = n 0 (1+)
add :: Nat -> Nat -> Nat
add (Nat a) b = a b inc
Now the Nat type is a real data type, which helps the type checker, because it doesn't have to deal with the polymorphic type all the time, only when you actually "unpack" it.
Here's my implementation of Church numerals:
type Nat = forall a . (a→a) → (a→a)
zero :: Nat
zero _ = id
one :: Nat
one = id
inc :: Nat → Nat
inc a f = f . a f
add :: Nat → Nat → Nat
add a b f = (a f) . (b f)
mul :: Nat → Nat → Nat
mul a b = a . b
nat :: Integer → Nat
nat 0 = zero
nat n = inc $ nat (n-1)
unnat :: Nat → Integer
unnat f = f (+ 1) 0
It is much easier to work with them flipped (function to apply N times first, its argument second). Everything just comes out, well, naturally.
EDIT: this solution is also limited, the types are not right just like in the original question and it will break down at some point.
It seems that by using Data.Proxy we can give a hint to GHC:
{-# LANGUAGE RankNTypes #-}
import Data.Proxy
type Nat = forall a. Proxy a -> (a -> a) -> (a -> a)
zero :: Nat
zero _ _ x = x
suc :: Nat -> Nat
suc n proxy s z = n proxy s (s z)
-- add = \m n f x. m f (n f x)
add :: Nat -> Nat -> Nat
add n m proxy s z = n proxy s (m proxy s z)
-- mult = \m n f. m (n f)
mult :: Nat -> Nat -> Nat
mult m n proxy s z = m proxy (n proxy s) z
And then it works!
λ > :t let one = suc zero in add one one
let one = suc zero in add one one :: Proxy a -> (a -> a) -> a -> a
λ > let one = suc zero in add one one Proxy (1+) 0
2
λ > :t let two = suc (suc zero) in mult two two
let two = suc (suc zero) in mult two two
:: Proxy a -> (a -> a) -> a -> a
λ > let two = suc (suc zero) in mult two two Proxy (1+) 0
4

Resources