I'm following the amb tutorial for Redex and, at the same time, building a model for typed arithmetic expressions, as found in Pierce's Types and Programming Languages.
I have defined the syntax and type system for such small language, but I'm in trouble to define its small step semantics. Before I got to the problems, let me present the definitions I've got so far.
First, I've defined the syntax of the language.
(define-language ty-exp
[E (ttrue)
(ffalse)
(zero)
(suc E)
(ppred E)
(iszero E)
(iff E E E)]
[T (nat)
(bool)])
Next, I defined the type system without problems.
(define-judgment-form ty-exp
#:mode (types I O)
#:contract (types E T)
[
----------------------"T-zero"
(types (zero) (nat))
]
[
-------------------------- "T-false"
(types (ffalse) (bool))
]
[
-------------------------- "T-true"
(types (ttrue) (bool))
]
[
(types E (nat))
-------------------------- "T-suc"
(types (suc E) (nat))
]
[
(types E (nat))
-------------------------- "T-pred"
(types (ppred E) (nat))
]
[
(types E (nat))
-------------------------- "T-iszero"
(types (iszero E) (bool))
]
[
(types E_1 (bool))
(types E_2 T_1)
(types E_3 T_1)
-------------------------- "T-iff"
(types (iff E_1 E_2 E_3) (T_1))
]
)
As far as I understand, we need to define semantics using evaluation contexts. So my next step was to define such contexts and values for the language.
(define-extended-language ty-exp-ctx-val ty-exp
(C (suc C)
(ppred C)
(iszero C)
(iff C E E)
hole)
(NV (zero)
(suc NV))
(BV (ttrue)
(ffalse))
(V (NV)
(BV)))
Non-terminal C stands for contexts, NV for numerical values, BV for boolean values and V for values. Using the definition of values, I defined a function for testing if an expression is a value.
(define v? (redex-match ty-exp-ctx-val V))
Using this setup, I tried to defined the operational semantics for this language.
In Pierce's book, such semantics (without evaluation contexts) is as follows:
e --> e'
---------------- (E-suc)
suc e --> suc e'
------------------ (E-pred-zero)
pred zero --> zero
NV e
------------------- (E-pred-succ)
pred (suc e) --> e
e --> e'
------------------- (E-pred)
pred e --> pred e'
-------------------- (E-iszero-zero)
iszero zero --> true
NV e
------------------------ (E-iszero-succ)
iszero (suc e) --> false
e --> e'
-------------------------(E-iszero)
iszero e --> iszero e'
---------------------- (E-if-true)
if true e e' --> e
-----------------------(E-if-false)
if false e e' --> e'
e --> e'
-----------------------(E-if)
if e e1 e2 --> if e' e1 e2
In order to express such semantics using evaluation contexts, I removed rules
E-suc, E-pred, E-izero and E-if and defined a rule for stepping in an
expression context:
e --> e'
--------------(E-context)
E[e] --> E[e']
As far as I understand, we don't need to represent such context rule in redex. So,
I have defined the semantics for this language as:
(define red
(reduction-relation
ty-exp-ctx-val
#:domain E
(--> (in-hole C (iff (ttrue) E_1 E_2))
(in-hole C E_1)
"E-if-true")
(--> (in-hole C (iff (ffalse) E_1 E_2))
(in-hole C E_2)
"E-if-false")
(--> (in-hole C (iszero (zero)))
(in-hole C (ttrue))
"E-iszero-zero")
(--> (in-hole C (iszero (suc (E))))
(in-hole C (ffalse))
(side-condition (v? (term E)))
"E-iszero-suc")
(--> (in-hole C (ppred (zero)))
(in-hole C (zero))
"E-pred-zero")
(--> (in-hole C (ppred (suc (E))))
(in-hole C (E))
(side-condition (v? (term E)))
"E-pred-suc")
))
Now, we come to the problem: When I tried to execute
(traces red (term (iif (iszero zero) ttrue ffalse)))
Racket returns the following error message:
reduction-relation: relation not defined for (iif (iszero (zero)) (ttrue) (ffalse))
Surely, I'm doing something silly, but I can't figure out what. Could someone help me with this?
After running the program, I see what the problem is.
Try:
(traces red (term (iff (iszero (zero)) (ttrue) (ffalse))))
In
(define-language ty-exp
[E (ttrue)
(ffalse)
(zero)
(suc E)
(ppred E)
(iszero E)
(iff E E E)]
[T (nat)
(bool)])
you have parentheses around ttrue, ffalse and zero.
Related
I am struggling to describe what it means for terms and literals (first order logic) to be re-written. Ie I would like a function applySubstitution that can be called on both terms and literals.
I thought that the substitution could be expressed as a function. However I am getting rigid type variable errors with the following code.
{-# LANGUAGE UnicodeSyntax #-}
module Miniexample where
import qualified Data.Maybe as M
data Term a = F a [Term a]
| V a
data Literal a = P a [Term a]
| E (Term a) (Term a)
class Substitutable b where
substitute :: b -> (Term a -> Maybe (Term a)) -> b
instance Substitutable (Term a) where
substitute x#(V _) σ = M.fromMaybe x (σ x)
substitute f#(F l xs) σ = M.fromMaybe f' (σ f)
where f' = F l (map (flip substitute σ) xs)
instance Substitutable (Literal a) where
substitute (P l xs) σ = P l (map (flip substitute σ) xs)
substitute (E s t) σ = E (substitute s σ) (substitute t σ)
class Substitution σ where
asSub :: σ -> (a -> Maybe a)
applySubstitution σ t = substitute t (asSub σ)
(<|) t σ = applySubstitution σ t
This gives be the following error:
• Couldn't match type ‘a1’ with ‘a’
‘a1’ is a rigid type variable bound by
the type signature for:
substitute :: forall a1.
Term a -> (Term a1 -> Maybe (Term a1)) -> Term a
at /.../Miniexample.hs:16:3-12
‘a’ is a rigid type variable bound by
the instance declaration
at /.../Miniexample.hs:15:10-31
Expected type: Term a1
Actual type: Term a
• In the first argument of ‘σ’, namely ‘x’
In the second argument of ‘M.fromMaybe’, namely ‘(σ x)’
In the expression: M.fromMaybe x (σ x)
• Relevant bindings include
σ :: Term a1 -> Maybe (Term a1)
(bound at /.../Miniexample.hs:16:22)
x :: Term a
(bound at /.../Miniexample.hs:16:14)
substitute :: Term a -> (Term a1 -> Maybe (Term a1)) -> Term a
(bound at /.../Miniexample.hs:16:3)
In my head, the type variable b in the Substitutable class should be able to take on (bad terminology I'm sure) the the value of Term a.
Any hints would be greatly welcome.
To give a more concrete example, the following works, but one needs to be explicit about which function applyTermSub or applyLitSub to call and secondly the implementation of the substitution map leaks into the implementation of the more general procedure.
module Miniexample where
import qualified Data.Maybe as M
import qualified Data.List as L
data Term a = F a [Term a]
| V a deriving (Eq)
data Literal a = P a [Term a]
| E (Term a) (Term a) deriving (Eq)
termSubstitute :: (Term a -> Maybe (Term a)) -> Term a -> Term a
termSubstitute σ x#(V _) = M.fromMaybe x (σ x)
termSubstitute σ f#(F l xs) = M.fromMaybe f' (σ f)
where f' = F l (map (termSubstitute σ) xs)
litSubstitute :: (Term a -> Maybe (Term a)) -> Literal a -> Literal a
litSubstitute σ (P l xs) = P l (map (termSubstitute σ) xs)
litSubstitute σ (E s t) = E (termSubstitute σ s) (termSubstitute σ t)
applyTermSub :: (Eq a) => Term a -> [(Term a, Term a)] -> Term a
applyTermSub t σ = termSubstitute (flip L.lookup σ) t
applyLitSub :: (Eq a) => Literal a -> [(Term a, Term a)] -> Literal a
applyLitSub l σ = litSubstitute (flip L.lookup σ) l
-- variables
x = V "x"
y = V "y"
-- constants
a = F "a" []
b = F "b" []
-- functions
fa = F "f" [a]
fx = F "f" [x]
σ = [(x,y), (fx, fa)]
test = (applyLitSub (P "p" [x, b, fx]) σ) == (P "p" [y, b, fa])
Ideally I would like to have an interface for substitutions (i.e one could use Data.Map etc) and secondly I would like a single substitute function that captures both term and literals.
The error you're getting is a complaint that Term a, as specified in instance Substitutable (Term a), is not the same type as the Term a that σ accepts. This is because Haskell quantifies a over the substitute function, but not over the rest of the instance definition. So an implementation of substitute must accept a σ that handles Term a1 for some value of a1, which is not guaranteed to be the specific a that your instance is defined on. (Yes, your instance is defined over all a... but from inside the scope of the instance definition, it's as if a specific a has been chosen.)
You can avoid this by parameterizing your Substitutable class by a type constructor instead of just a type, and passing the same a to that type constructor as is used in the σ type.
{-# LANGUAGE UnicodeSyntax #-}
import qualified Data.Maybe as M
import qualified Data.List as L
data Term a = F a [Term a]
| V a deriving (Eq)
data Literal a = P a [Term a]
| E (Term a) (Term a) deriving (Eq)
class Substitutable f where
substitute :: f a -> (Term a -> Maybe (Term a)) -> f a
instance Substitutable Term where
substitute x#(V _) σ = M.fromMaybe x (σ x)
substitute f#(F l xs) σ = M.fromMaybe f' (σ f)
where f' = F l (map (flip substitute σ) xs)
instance Substitutable Literal where
substitute (P l xs) σ = P l (map (flip substitute σ) xs)
substitute (E s t) σ = E (substitute s σ) (substitute t σ)
(<|) t σ = substitute t $ flip L.lookup σ
-- variables
x = V "x"
y = V "y"
-- constants
a = F "a" []
b = F "b" []
-- functions
fa = F "f" [a]
fx = F "f" [x]
σ = [(x,y), (fx, fa)]
main = print $ show $ (P "p" [x, b, fx] <| σ) == P "p" [y, b, fa]
S e :=
| def: (forall e', S e' -> S (App e e')) -> S e
I am trying to write logical relations based proof of strong normalization in Coq.
You can write it as a Fixpoint over the structure of expressions:
Inductive expr :=
| Var (n:nat)
| Abs (n:nat) (e:expr)
| App (e1 e2: expr).
Fixpoint S (e:expr) : Prop :=
match e with
| Var n => True
| Abs n e => True
| App e1 e2 => S e2
end.
Note that you can't say something like forall e', S e' -> subst e n e' in the Abs case because it doesn't recurse on a subterm. Instead, though, you can recurse on the structure of the type of e. I worked on something like this for Gödel's System T (lambda calculus with recursion over natural numbers): see https://github.com/tchajed/goedel-t/blob/master/SystemT.v#L538.
Every time I define a language in PLT redex, I need to manually define a (capture-avoiding) substitution function. For example, this model isn't finished because subst isn't defined:
#lang racket/base
(require redex/reduction-semantics)
(define-language Λ
[V ::= x (λ x M)]
[M ::= (M M) V]
[C ::= hole (V C) (C M)]
[x ::= variable-not-otherwise-mentioned])
(define -->β
(reduction-relation Λ
[--> (in-hole C ((λ x M) V))
(in-hole C (subst M x V))]))
But the definition of subst is obvious. Can PLT redex handle substitution automatically?
Yes! Just describe your language's binding structure with a #:binding-forms declaration.
Here's a similar model with capture-avoiding substitution via the substitute function:
#lang racket/base
(require redex/reduction-semantics)
(define-language Λ
[V ::= x (λ x M)]
[M ::= (M M) V]
[C ::= hole (V C) (C M)]
[x ::= variable-not-otherwise-mentioned]
#:binding-forms
(λ x M #:refers-to x)) ;; "term M refers to the variable x"
(define -->β
(reduction-relation Λ
[--> (in-hole C ((λ x M) V))
(in-hole C (substitute M x V))]))
(apply-reduction-relation -->β
(term ((λ x (λ y x)) y)))
;; '((λ y«2» y))
Alphabetic equivalence comes for free too, see alpha-equivalent?
(Thank you Paul Stansifer!)
A common way of defining semantics is (for example):
return v if [some other condition]
otherwise, return error
For example, consider
(define-language simple-dispatch
(e ::= v (+ e e))
(v ::= number string)
(res ::= e err)
(E ::= hole (+ E e) (+ v E)))
We could then define the reduction relation
(define s-> (reduction-relation simple-dispatch
#:domain res
(--> (in-hole E (+ number_1 number_2))
(in-hole E ,(+ number_1 number_2)))
(--> (in-hole E (+ any any))
err)))
This is the natural way to do this, because it avoids having to write individual matchers for each of the 3 failure cases (number string, string number, string string). However, it then creates the problem that running it like this:
(apply-reduction-relation s-> (term (+ 2 2)))
Shows (correctly) that it lets you reduce both to an error or to the number 4. Is there a way to make an "except" pattern that avoids having to check all of the constituent cases?
What you want to use here is a combination of side-condition and redex-match?. Extending your reduction-relation gives:
(define s-> (reduction-relation simple-dispatch
#:domain res
(--> (in-hole E (+ number_1 number_2))
(in-hole E ,(+ (term number_1) (term number_2))))
(--> (in-hole E (+ any_1 any_2))
err
(side-condition
(not (redex-match? simple-dispatch
(+ number number)
(term (+ any_1 any_2))))))))
This just says you can take the second rule so long as the first one is not true, which is what the papers are saying implicitly, and just didn't draw out explicitly in the figure. (Note that you can use side-condition/hidden to get it to not draw the side condition when rendering the figure).
You can use this method to scale up to any number of patterns you want to disallow.
I have some function like
(A and ( B or c)) or (D and E and (F or H or R or P )))
and I want to convert that function to function with only and operations (of course if possible)
I find that with DeMorgan's Laws can be done some kind of transformations but I didn't manage to conver this function any ideas ?
I know that function
!(A or B) is equal to function !A and !B
but I could not find the equal function to the one above
The function you mentioned:
!(A or B) = !A and !B
is the same as:
A or B = !(!A and !B)
So let's start by splitting your problem into two parts of ABC and DEFHRP.
(A and (B or C)) = (A and !(!B and !C))
(D and E and (F or H or R or P)) = (D and E and !(!F and !H and !R and !P))
Since these two parts are joined by an 'or', we can apply the equivalence again to get:
!(!(A and !(!B and !C)) and !(D and E and !(!F and !H and !R and !P)))
The key substitution you're looking for is A OR B => !(!A AND !B). Using this you can expand the expression.
a and (b or c)
is the same as
a and not (not b and not c)
You can test it here
And for the more complex one:
d and e and (f or h or r)
is the same as
d and e and not(not f and not h and not r)
which is tested here