Proof trees for simply typed lambda calculus - lambda-calculus

I need to state the type of the term
((λx : int. (x ≤ 1)) 2)
and prove it using a proof tree. I'm fairly certain that this is taking 2 as an input for x, then comparing 2 to 1 and returning a boolean. This means the type of the term would be int → boolean. I'm just not sure how to write a proof tree for it. If someone could point me towards some examples or explain how to do a similar problem that would be great.

I assume you are talking about the simply typed lambda calculus extended with the datatypes int and boolean, the terms _≤_, 1 and 2, and the typing derivation rules
--------------------------------
Γ ⊢ _≤_ : int → int → boolean
------------
Γ ⊢ 1 : int
------------
Γ ⊢ 2 : int
Using these, and the standard STLC typing rules, the type of your term is not int → boolean, rather, it is boolean as we will see below. Also, it β-reduces to 2 ≤ 1, so that should show you quite easily that it is a boolean.
But now to the meat of it: the typing derivation tree:
{x : int} ⊢ _≤_ : int → int → boolean {x : int} ⊢ x : int
----------------------------------------------------------------
{x : int} ⊢ x ≤_ : int → boolean {x: int} ⊢ 1 : int
--------------------------------------------------------------------
{x: int} ⊢ x ≤ 1 : boolean
To save on horizontal space, let's do the rest in a new tree:
{x: int} ⊢ x ≤ 1 : boolean
----------------------------------------
{} ⊢ (λx : int. (x ≤ 1) : int → boolean {} ⊢ 2 : int
-------------------------------------------------------------------
{} ⊢ ((λx : int. (x ≤ 1)) 2) : boolean ∎

Related

Ocaml - writing a function who's number of arguments is determined at runtime

I want to write a function f, that takes n arguments, where n is determined at runtime, and might vary at every call to the function, for example
let's say our function f takes an integer n which is the number of args, and n args of the same type and turns them into a list:
# f 3 'a' 'b' 'c';;
- : char list = ['a'; 'b'; 'c']
# f 2 1 2;;
- : int list = [1; 2]
I thaught of something like
let f acc n x =
if n = 0
then List.rev (x::acc)
else f [x] (x - 1)
but in this case it won't work because of the type difference.
Using currying, you can do something that resembles variadic functions, but you’ll have to convince the type checker. You will not be able to conveniently provide the arity of your function as a bare integer; instead, you can unary-encode the arity as a value of a GADT:
type (_, 'r) arity =
| O : ('r, 'r) arity
| I : ('f, 'r) arity -> (int->'f, 'r) arity
The encoding works as follows:
O : ('r, 'r) arity represents the arity of a “function that takes no argument” and returns an 'r;
I O : (int -> 'r, 'r) arity represents the arity of a function that takes an int and then returns an 'r;
I (I O) : (int -> int -> 'r, 'r) arity represents the arity of a function that takes two ints and then returns an 'r;
I (I (I O)) : (int -> int -> int -> 'r, 'r) arity is the arity of a function that takes three ints and then returns an 'r;
etc.
Instead of passing 3 as a first argument to your hypothetical variadic function, you would pass I (I (I O)). This value describes the sequence of arguments that the function is supposed to take (one int, then one int, then one int, then return). The function would then proceed recursively, destructing (inspecting) this description to decide what to do next You can implement your example function that builds the list of all its arguments, like so:
let rec f_aux : type f. int list -> (f, int list) arity -> f =
fun acc arity ->
begin match arity with
| O -> List.rev acc
| I a -> fun x -> f_aux (x :: acc) a
end
let f arity = f_aux [] arity
# f (C(C(C O))) ;;
- : int -> int -> int -> int list = <fun>
# f (C(C(C O))) 111 222 333 ;;
- : int list = [111; 222; 333]
As is common with GADTs, type inference is not enough and you have to annotate your definition with the intended type, including an explicit universal quantification (type f. … where f is the type variable being quantified).
The GADT defined above can only describe variadic functions that deal with ints, but notice that you can easily extend it to allow more types of arguments (then of course, you should adapt your variadic functions so that they deal with these added possibilities):
type (_, 'r) arity =
| O : ('r, 'r) arity
| I : ('f, 'r) arity -> (int->'f, 'r) arity
| B : ('f, 'r) arity -> (bool->'f, 'r) arity
| C : ('f, 'r) arity -> (char->'f, 'r) arity
| S : ('f, 'r) arity -> (string->'f, 'r) arity
(* etc. *)
let rec g_aux : type f. string -> (f, string) arity -> f =
fun acc arity ->
begin match arity with
| O -> acc
| I a -> fun x -> g_aux (acc ^ string_of_int x) a
| B a -> fun x -> g_aux (acc ^ if x then "true" else "false") a
| C a -> fun x -> g_aux (acc ^ String.make 1 x) a
| S a -> fun x -> g_aux (acc ^ x) a
(* etc. *)
end
let g arity = g_aux "" arity
# g (S(I(S(B(C O))))) ;;
- : string -> int -> string -> bool -> char -> string = <fun>
# g (S(I(S(B(C O))))) "Number " 42 " is prime. I swear, it’s " true '!' ;;
- : string = "Number 42 is prime. I swear, it’s true!"
As a matter of fact, this is essentially how pretty-printing is implemented in OCaml: when you write Printf.printf "%s%b" …, the format string is not actually a string, it is syntactic sugar kindly supplied by the compiler for a value of some very complicated GADT type such as (_,_,_,_,_,_) format6 (6 type parameters!). You might just as well build the GADT value by hand (don’t). This syntactic sugar is the only magic that the compiler does for pretty-printing, everything else works with standard language features.
Well, we have a system that works, at least it typechecks. Syntax is not pretty unless the compiler gives you sugar. More importantly, arities are encoded and checked within the static type system, which means, they are known at compile-time. You cannot (or at least it’s hard to do safely) read an arity as input of your program, dynamically, at run-time.
The actual question is: why would you actually need to do that, instead of just using a list? It brings nothing except syntactic convenience perhaps.
Your requirement doesn't make sense, since there is no way to dynamically change the number of parameters of a function at runtime. The number of parameters in any function call is directly visible by examining the text of the source code:
f a b (* Two parameters *)
f a b c (* Three parameters *)
There is no dynamic evaluation mechanism in OCaml (like the eval mechanism of other languages). This is part of what it means to be statically typed.
You can get the effect you want just by passing a list to the function.

Formulating a dependent type system in Agda

How would one formulate a dependently-typed logic in Agda, but not "cheating" by re-using the Agda type system itself?
I can quite readily define an independently-typed logic:
infixr 5 _⇒_
data Type : Set where
_⇒_ : Type → Type → Type
infix 4 _⊢_
data _⊢_ : List Type → Type → Set where
var : {a : Type} → [ a ] ⊢ a
λ' : {a b : Type} {γ : _} → a ∷ γ ⊢ b → γ ⊢ a ⇒ b
ply : {a b : Type} {γ δ : _} → γ ⊢ a ⇒ b → δ ⊢ a → γ ++ δ ⊢ b
weak : {a b : Type} {γ : _} → γ ⊢ b → a ∷ γ ⊢ b
cntr : {a b : Type} {γ : _} → a ∷ a ∷ γ ⊢ b → a ∷ γ ⊢ b
xchg : {a : Type} {γ δ : _} → γ ↭ δ → γ ⊢ a → δ ⊢ a
I can also roughly follow the LambdaPi tutorial implementation of dependently-typed λ-calculus in Haskell. But it's implictly-typed, unlike my Agda code, and i'm not sure where to even begin to modify my code, as the path which came to mind so far led to infinite regress:
data _⊢_ : List (? ⊢ ?) → (? ⊢ ?) → Set where ...
Google searches for "embedding dependent types in Agda" and the like merely return hits for dependently-typed programming in Agda...
We have done this in our paper on Type Theory in Type Theory which is actually formalised in Agda. The basic idea is that you define Contexts, Types, Terms and Substitutions as a mutual inductive definition. We only define typed objects so we never have to define untyped things or a typing judgement. Typing is defined via dependency so for example types depend on contexts and terms on types and contexts. To formulate definitional equality we use ideas from Homotopy Type Theory and allow equality constructors. This meant that we had to axiomatise instances of higher inductive types or to be precise quotient inductive inductive types. This should be soon possible out of the box in cubical Agda.
http://www.cs.nott.ac.uk/~psztxa/publ/tt-in-tt.pdf
#article{altenkirch2016type,
title={Type theory in type theory using quotient inductive types},
author={Altenkirch, Thorsten and Kaposi, Ambrus},
journal={ACM SIGPLAN Notices},
volume={51},
number={1},
pages={18--29},
year={2016},
publisher={ACM}
}

Using Implicit Type Class Parameters in Coq Notation

I'm trying to wrap my head around type classes in Coq (I've dabbled with it in the past, but I'm a far cry from being an experienced user). As an exercise, I am trying to write a group theory library. This is what I've come up with:
Class Group {S : Type} {op : S → S → S} := {
id : S;
inverse : S → S;
id_left {x} : (op id x) = x;
id_right {x} : (op x id) = x;
assoc {x y z} : (op (op x y) z) = (op x (op y z));
right_inv {x} : (op x (inverse x)) = id;
}.
I am particularly fond of the implicit S and op parameters (assuming I understand them correctly).
Making some notation for inverses is easy:
Notation "- x" := (#inverse _ _ _ x)
(at level 35, right associativity) : group_scope.
Now, I would like to make x * y a shorthand for (op x y). When working with sections, this is straightforward enough:
Section Group.
Context {S} {op} { G : #Group S op }.
(* Reserved at top of file *)
Notation "x * y" := (op x y) : group_scope.
(* ... *)
End Group.
However, since this is declared within a section, the notation is inaccessible elsewhere. I would like to declare the notation globally if possible. The problem I am running into (as opposed to inverse) is that, since op is an implicit parameter to Group, it doesn't actually exist anywhere in the global scope (so I cannot refer to it by (#op _ _ _ x y)). This problem indicates to me that I am either using type classes wrong or don't understand how to integrate notation with implicit variables. Would someone be able to point me in the right direction?
Answer (25 Jan 2018)
Based on Anton Trunov's response, I was able to write the following, which works:
Reserved Notation "x * y" (at level 40, left associativity).
Class alg_group_binop (S : Type) := alg_group_op : S → S → S.
Delimit Scope group_scope with group.
Infix "*" := alg_group_op: group_scope.
Open Scope group_scope.
Class Group {S : Type} {op : alg_group_binop S} : Type := {
id : S;
inverse : S → S;
id_left {x} : id * x = x;
id_right {x} : x * id = x;
assoc {x y z} : (x * y) * z = x * (y * z);
right_inv {x} : x * (inverse x) = id;
}.
Here is how Pierre Castéran and Matthieu Sozeau solve this problem in A Gentle Introduction to Type Classes and Relations in Coq (§3.9.2):
A solution from ibid. consists in declaring a singleton type class for representing binary operators:
Class monoid_binop (A:Type) := monoid_op : A -> A -> A.
Nota: Unlike multi-field class types, monoid_op is not a constructor, but a transparent constant such that monoid_op f can be δβ-reduced into f.
It is now possible to declare an infix notation:
Delimit Scope M_scope with M.
Infix "*" := monoid_op: M_scope.
Open Scope M_scope.
We can now give a new definition of Monoid, using the type monoid_binop A instead of A → A → A, and the infix notation x * y instead of monoid_op x y :
Class Monoid (A:Type) (dot : monoid_binop A) (one : A) : Type := {
dot_assoc : forall x y z:A, x*(y*z) = x*y*z;
one_left : forall x, one * x = x;
one_right : forall x, x * one = x
}.
There's probably a good reason why Pierre Castéran and Matthiu Sozeau deal with it that way.
But wouldn't
Definition group_op {S op} {G : #Group S op} := op.
Infix "*" := group_op.
also work here? (I only tried on two very basic test cases.)
This would spare you changing definition of Group.

Generic algorithm to enumerate sum and product types on Haskell?

Some time ago, I've asked how to map back and forth from godel numbers to terms of a context-free language. While the answer solved the issue specificaly, I'm having trouble in actually programming it generically. So, this question is more generic: given a recursive algebraic data type with terminals, sums and products - such as
data Term = Prod Term Term | SumL Term | SumR Term | AtomA | AtomB
what is an algorithm that will map a term of this type to its godel number, and its inverse?
Edit: for example:
data Foo = A | B Foo | C Foo deriving Show
to :: Foo -> Int
to A = 1
to (B x) = to x * 2
to (C x) = to x * 2 + 1
from :: Int -> Foo
from 1 = A
from n = case mod n 2 of
0 -> B (from (div n 2))
1 -> C (from (div n 2))
Here, to and from do what I want for Foo. I'm just asking for a systematic way to derive those functions for any datatype.
In order to avoid dealing with a particular Goedel numbering, let's define a class that'll abstract the necessary operations (with some imports we'll need later):
{-# LANGUAGE TypeOperators, DefaultSignatures, FlexibleContexts, DeriveGeneric #-}
import Control.Applicative
import GHC.Generics
import Test.QuickCheck
import Test.QuickCheck.Gen
class GodelNum a where
fromInt :: Integer -> a
toInt :: a -> Maybe Integer
encode :: [a] -> a
decode :: a -> [a]
So we can inject natural numbers and encode sequences. Let's further create a canonical instance of this class that'll use throughout the code, which does no real Goedel encoding, just constructs a tree of terms.
data TermNum = Value Integer | Complex [TermNum]
deriving (Show)
instance GodelNum TermNum where
fromInt = Value
toInt (Value x) = Just x
toInt _ = Nothing
encode = Complex
decode (Complex xs) = xs
decode _ = []
For real encoding we'd use another implementation that'd use just one Integer, something like newtype SomeGoedelNumbering = SGN Integer.
Let's further create a class for types that we can encode/decode:
class GNum a where
gto :: (GodelNum g) => a -> g
gfrom :: (GodelNum g) => g -> Maybe a
default gto :: (Generic a, GodelNum g, GGNum (Rep a)) => a -> g
gto = ggto . from
default gfrom :: (Generic a, GodelNum g, GGNum (Rep a)) => g -> Maybe a
gfrom = liftA to . ggfrom
The last four lines define a generic implementation of gto and gfrom using GHC Generics and DefaultSignatures. The class GGNum that they use is a helper class which we'll use to define encoding for the atomic ADT operations - products, sums, etc.:
class GGNum f where
ggto :: (GodelNum g) => f a -> g
ggfrom :: (GodelNum g) => g -> Maybe (f a)
-- no-arg constructors
instance GGNum U1 where
ggto U1 = encode []
ggfrom _ = Just U1
-- products
instance (GGNum a, GGNum b) => GGNum (a :*: b) where
ggto (a :*: b) = encode [ggto a, ggto b]
ggfrom e | [x, y] <- decode e = liftA2 (:*:) (ggfrom x) (ggfrom y)
| otherwise = Nothing
-- sums
instance (GGNum a, GGNum b) => GGNum (a :+: b) where
ggto (L1 x) = encode [fromInt 0, ggto x]
ggto (R1 y) = encode [fromInt 1, ggto y]
ggfrom e | [n, x] <- decode e = case toInt n of
Just 0 -> L1 <$> ggfrom x
Just 1 -> R1 <$> ggfrom x
_ -> Nothing
-- metadata
instance (GGNum a) => GGNum (M1 i c a) where
ggto (M1 x) = ggto x
ggfrom e = M1 <$> ggfrom e
-- constants and recursion of kind *
instance (GNum a) => GGNum (K1 i a) where
ggto (K1 x) = gto x
ggfrom e = K1 <$> gfrom e
Having that, we can then define a data type like yours and just declare its GNum instance, everything else will be automatically derived.
data Term = Prod Term Term | SumL Term | SumR Term | AtomA | AtomB
deriving (Eq, Show, Generic)
instance GNum Term where
And just to be sure we've done everything right, let's use QuickCheck to verify that our gfrom is an inverse of gto:
instance Arbitrary Term where
arbitrary = oneof [ return AtomA
, return AtomB
, SumL <$> arbitrary
, SumR <$> arbitrary
, Prod <$> arbitrary <*> arbitrary
]
prop_enc_dec :: Term -> Property
prop_enc_dec x = Just x === gfrom (gto x :: TermNum)
main :: IO ()
main = quickCheck prop_enc_dec
Notes:
The same thing could be accomplished using Scrap Your Boilerplate, perhaps more efficiently, as it allows somewhat higher-level access - enumerating constructors and records, etc.
See also paper Efficient Bijective G¨odel Numberings for Term Algebras (I haven't read the paper yet, but seems related).
For fun, I decided to try the approach in the link you posted, and didn't get stuck anywhere. So here's my code, with no commentary (the explanation is the same as the last time). First, code stolen from the other answer:
{-# LANGUAGE TypeSynonymInstances #-}
import Control.Applicative
import Data.Universe.Helpers
type Nat = Integer
class Godel a where
to :: a -> Nat
from :: Nat -> a
instance Godel Nat where to = id; from = id
instance (Godel a, Godel b) => Godel (a, b) where
to (m_, n_) = (m + n) * (m + n + 1) `quot` 2 + m where
m = to m_
n = to n_
from p = (from m, from n) where
isqrt = floor . sqrt . fromIntegral
base = (isqrt (1 + 8 * p) - 1) `quot` 2
triangle = base * (base + 1) `quot` 2
m = p - triangle
n = base - m
And the code specific to your new type:
data Term = Prod Term Term | SumL Term | SumR Term | AtomA | AtomB
deriving (Eq, Ord, Read, Show)
ts = AtomA : AtomB : interleave [uncurry Prod <$> ts +*+ ts, SumL <$> ts, SumR <$> ts]
instance Godel Term where
to AtomA = 0
to AtomB = 1
to (Prod t1 t2) = 2 + 0 + 3 * to (t1, t2)
to (SumL t) = 2 + 1 + 3 * to t
to (SumR t) = 2 + 2 + 3 * to t
from 0 = AtomA
from 1 = AtomB
from n = case quotRem (n-2) 3 of
(q, 0) -> uncurry Prod (from q)
(q, 1) -> SumL (from q)
(q, 2) -> SumR (from q)
The same ghci test as last time:
*Main> take 30 (map from [0..]) == take 30 ts
True

How to formalize the definition of likeness/similarity between relations in Coq?

I am reading the book Introduction to Mathematics Philosophy by B.Russell and trying to formalize the definitions. Whereas I got stuck on proving the equivalence between the two definitions of similarity posed in the book.
Here are the text quoted from the book. (context)
1) Defining similarity directly:
We may define two relations P and Q as “similar,” or as having
“likeness,” when there is a one-one relation S whose domain is the
field of P and whose converse domain is the field of Q, and which is
such that, if one term has the relation P to another, the correlate of
the one has the relation Q to the correlate of the other, and vice
versa.
Here's my comprehension of the above text:
Inductive similar {X} (P : relation X) (Q : relation X) : Prop :=
| similar_intro : forall (S : relation X),
one_one S ->
(forall x, field P x <-> domain S x) ->
(forall x y z w, P x y -> S x z -> S y w -> Q z w) ->
(forall x y z w, Q z w -> S x z -> S y w -> P x y) ->
similar P Q.
2) Defining similarity through the concept of 'correlator':
A relation S is said to be a “correlator” or an “ordinal correlator”
of two relations P and Q if S is one-one, has the field of Q for its
converse domain, and is such that P is the relative product of S and Q
and the converse of S.
Two relations P and Q are said to be “similar,” or to have “likeness,”
when there is at least one correlator of P and Q.
My definition to this is:
Inductive correlator {X} (P Q : relation X) : relation X -> Prop :=
| correlator_intro : forall (S : relation X),
one_one S ->
(forall x, field P x <-> domain S x) ->
(forall x y, relative_product (relative_product S Q) (converse S) x y <-> P x y) ->
correlator P Q S.
Inductive similar' {X} (P Q : relation X) : Prop :=
| similar'_intro : forall S, correlator P Q S -> similar' P Q.
But I couldn't prove that similar is equivalent to similar', where did I make the mistake? Thanks a lot.

Resources