0% found this document useful (0 votes)
21 views25 pages

Inductive Sets of Data: Essentials of Programming Languages (Chapter 1)

The document discusses inductive sets of data and their specifications in programming languages, focusing on recursive definitions and rules of inference. It presents top-down and bottom-up definitions for natural numbers and lists of integers, along with examples of how to derive membership in these sets. Additionally, it covers context-free and context-sensitive grammars, lambda calculus, and procedures for manipulating lists and expressions.

Uploaded by

pouriakhamseh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views25 pages

Inductive Sets of Data: Essentials of Programming Languages (Chapter 1)

The document discusses inductive sets of data and their specifications in programming languages, focusing on recursive definitions and rules of inference. It presents top-down and bottom-up definitions for natural numbers and lists of integers, along with examples of how to derive membership in these sets. Additionally, it covers context-free and context-sensitive grammars, lambda calculus, and procedures for manipulating lists and expressions.

Uploaded by

pouriakhamseh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 25

Inductive Sets of Data

Essentials of Programming Languages (Chapter 1)

Session 6
Recursively Specified Data
 We introduce the basic programming tools to write interpreters, ...
 The syntax of a language is usually a nested or treelike structure
- Recursion will be at the core of our techniques
 We must know
- What kinds of values may occur as arguments to the procedure?
- What kinds of values are legal for the procedure to return?

Often these sets of values are complex


Inductive Specification (top-down definition)
Powerful method for specifying a set of values
S {0, 1, 2,...}

Definition 1.1.1 A natural number n is in S if and only if


1. n=0 , or
2. n -3 S.

If n is a natural number and is not a multiple of 3, then n S.


Inductive Specification
in-S? N  Bool
usage: (in-s? n) = #t if n is in S, #f otherwise
(define in-S?
(lambda (n)
(if (zero? n) #t
(if (>= (- n 3) 0)
(in-S? (- n 3))
#F))))

in-S?: N  Bool is a comment, called the contract


Inductive Specification (bottom-up definition)

Definition 1.1.2 Define the set S to be the smallest set contained in N


and satisfying the following two properties:

1. 0 S, and
2. If n S, then n+3 S.

• We need "smallest set":


Otherwise there are many sets that satisfy the remaining two conditions
Rules of Inference

• Each entry is called a rule of inference, or just a rule


• The horizontal line is read as an "if-then"
• The part above the line is called the hypothesis
• The part below the line is called the conclusion or the consequent
• Hypotheses are connected by an implicit "and"
• A rule with no hypotheses is called an axiom
Rules of Inference

• A natural number n is in S if and only if the statement "n ES" can be derived
from the axioms by using the rules of inference finitely many times

• This makes S the smallest set that is closed under the rules
• These definitions all say the same thing.
• the first version: a top-down definition
• the second version: a bottom-up definition
• the third version: a rules-of-inference version
Inductive Specification
• Definition 1.1.3 (list of integers, top-down) A Scheme list is a list of integers if
and only if either
1. it is the empty list, or
2. it is a pair whose car is an integer and whose cdr is a list of integers.

• Definition 1.1.4 (list of integers, bottom-up) The set List-of-Int is the smallest set of
Scheme lists satisfying the following two properties:

1. () List-of-Int, and
2. if n Int and l List-of-Int, then (n . l) List-of-Int.
Rules of Inference
Definition 1.1.5 (list of integers, rules of inference)
∈ List-of-int

𝑛 ∈ 𝑖𝑛𝑡 𝑙 ∈ 𝑙𝑖𝑠𝑡 − 𝑜𝑓 − 𝑖𝑛𝑡


(𝑛 . 𝑙) ∈ 𝑙𝑖𝑠𝑡 − 𝑜𝑓 − 𝑖𝑛𝑡
1- () is a list of integers, because of property 1 of definition 1.1.4 or the first rule of
definition 1.1.5.
2- (14 ()) is a list of integers, because of property 2 of definition 1.1.4, since 14 is a
integer and () is a list of integers. We can also write this as an instance of the second rule
for List-of-Int.
14 ∈ 𝑖𝑛𝑡 ( ) ∈ 𝑙𝑖𝑠𝑡 − 𝑜𝑓 − 𝑖𝑛𝑡
(14 . ( )) ∈ 𝑙𝑖𝑠𝑡 − 𝑜𝑓 − 𝑖𝑛𝑡
Rules of Inference
3- (3 . (14 . ())) is a list of integers, because of property 2, since 3 is an integer and (14 . ()) is
a list of integers. We can write this as another instance of the second rule for List-of-Int.

(14 . ())
(3 . (14 . ()))
4. (-7 . (3 . (14. ()))) is a list of integers, because of property 2, since -7 is a integer and (3 . (14 .
())) is a list of integers. Once more we can write this as an instance of the second rule for List-of-
Int.
−7 ∈ 𝑖𝑛𝑡 (3 . (14 . ()))∈ 𝑙𝑖𝑠𝑡 − 𝑜𝑓 − 𝑖𝑛𝑡
(−7 . (3 . (14 . ()))) ∈ 𝑙𝑖𝑠𝑡 − 𝑜𝑓 − 𝑖𝑛𝑡

5. Nothing is a list of integers unless it is built in this fashion.


Rules of Inference
We can combine the rules to get a picture of the entire chain of reasoning, called a derivation
or deduction tree

(14 . ())
(3 . (14 . ()))
(−7 . (3 . (14 . ())))
Defining Sets Using Grammars

List-of-Int::= ()
List-of-Int::= (Int . List-of-Int)

• In this definition, we have:


• Nonterminal Symbols
• Terminal Symbols
• Productions
Defining Sets Using Grammars
A syntactic derivation may be used to show that a given data value is a
member of the set
• starts with the nonterminal corresponding to the set
• at each step, a nonterminal is replaced

List-of-Int List-of-Int
 (Int . List-of-Int)  (Int . List-of-Int)
 (14 . List-of-Int)  (int . ())
 (14 . ())  (14 . ())
Other Useful Sets
Definition 1.1.6(S-list , S-exp) Definition 1.1.7(binary tree)
Bintree ::= int | (Symbol Bintree Bintree)
S-list ::= ({s−exp}∗ )
S-exp ::= Symbol | s-list
Here are some example of such tree
1
2
(foo 1 2)
(bar 1 (foo 1 2))
(baz
(bar 1 (foo 1 2)
(biz 4 5)
Other Useful Sets
The lambda calculus is a simple language that consists only of:
• variable references
• procedures that take a single argument
• procedure calls
Definition 1.1.8 (lambda expression)
LcExp ::= Identifier
::= (lambda (Identifier) LcExp)
::= (LcExp LcExp)
where an identifier is any symbol other than lambda.
Lambda Calculus
The identifier in the second production is called the bound variable
• It binds or captures any occurrences of the variable in the body
• Any occurrence of that variable in the body refers to this one

(lambda (x) (+ x 5))

((lambda (x) (+ x 5)) (- x 7))


Context-free Grammars
These grammars are said to be context-free
• Their rules may be applied in any context
• Sometimes this is not restrictive enough
Binary-search-tree ::= () | ( Int Binary-search-tree Binary-search-tree )
Binary search trees:
• All the keys in the left subtree are less than (or equal to) the key in the current node
• All the keys in the right subtree are greater than the key in the current node

To determine whether a particular production can be applied in a particular syntactic derivation:


• We have to look at the context
• Such constraints are called context-sensitive constraints or invariants
Context-sensitive Constraints
Context-sensitive constraints also arise when specifying the syntax of programming languages
• In many languages every variable must be declared
• This constraint on the use of variables is sensitive to the context

Formal methods can be used to specify context-sensitive constraints, but these


methods are far more complicated

The usual approach is first to specify a context-free grammar. Context-sensitive constraints


are then added using other methods
nth-element
(Procedure list-ref takes a list, Ist, and a zero-based index, n, and returns element number n of Ist
> (list-ref ‘ (a b c) 1)
b
nth-element: List x Int Scheme Val List::= () | (Scheme value. List)
usage: (nth-element lst n) = the n-th element of Ist
(define nth-element
(lambda (lst n)
(if (null? lst)
(report-list-too-short n) (nth-element ‘(a b c d e ) 3)
(if (zero? n) = (nth-element ‘(b c d e) 2)
(car lst) = (nth-element ‘(c d e) 1)
(nth-element (cdr lst) (-n 1)))))) = (nth-element ‘(d e) 0)
(define report-list-too-short =d
(lambda (n)
(eopl:error 'nth-element
"List too short by -s elements. (+ n 1))))
remove-first
The procedure remove-first should take two arguments: a symbol, s, and a list
of symbols, los
The first occurrence of the symbol s should be removed

remove-first: Sym × Listof(Sym) Listof(Sym) List-of-Symbol ::= () | (Symbol . List-of-Symbol)


(define remove-first
(lambda (s los) > (remove-first ‘a ‘(a b c))
(if (null? los) (b c)
‘() > (remove-first ‘b ‘(e f g))
(if (equal? (car los) s) (e f g)
(cdr los) > (remove-first ‘a4 ‘(cl a4 cl a4))
(cons (car los) (remove-first s (cdr los))))))) (cl cl a4)
> (remove-first ‘x ‘ ())
()
occurs-free?
A variable occurs free in an expression exp if it has some occurrence in exp
that is not inside some lambda binding of the same variable

>(occurs-free? ‘x ‘x) LcExp ::= Identifier


#t ::=(lambda (Identifier) LcExp)
>(occurs-free? ‘x 'y) ::=(LcExp LcExp)
#f
>(occurs-free? ‘x '(lambda (x) (x y)))
#f
>(occurs-free? ‘x ‘(lambda (y) (x y}}}
#t
>(occurs-free? ‘x ‘((lambda (x) x) (x y)))
#t
>(occurs-free? ‘x ‘(lambda (y) (lambda (z) (x (y z)))))
#t
occurs-free?
We can summarize these cases in the rules:

 If the expression e is a variable, then the variable x occurs free in e if


and only if x is the same as e.

 If the expression e is of the form (lambda (y) e'), then the variable x
occurs free in e if and only if y is different from x and x occurs free in e'.

 If the expression e is of the form (e1 e2) then x occurs free in e if


and only if it occurs free in e1 or e2. Here, we use "or" to mean
inclusive or, meaning that this includes the possibility that x occurs free in
both e1, and e2. We will generally use "or" in this sense.
occurs-free?
occurs-free?: Sym × LcExp Bool
usage: returns #t if the symbol var occurs free in exp, otherwise returns
#f.
(define occurs-free?
( lambda (var exp)
(cond
((symbol? exp) (equal? var exp))
((equal? (car exp) 'lambda )
(and
(not (equal? var (car (cadr exp))))
(occurs-free? var (caddr exp))))
(else
(or
(occurs-free? Var (car exp))
(occurs-free? var (cadr exp))))))
subst
The procedure subst should take three arguments: two symbols, new and old,
and an s-list, slist.
subst: Sym × Sym × S-list S-list S-list ::= ({S-exp}’)
(define subst S-exp ::= Symbol | S-list
(lambda (new old slist)
(if (null? slist)
‘ ()
(cons S-list ::= ()
(subst-in-s-exp new old (car slist)) ::= (S-exp . S-list)
(subst new old (cdr slist)))))) S-exp ::= Symbol | S-list

subst-in-s-exp: Sym × Sym × S-exp S-exp


(define subst-in-s-exp
(lambda (new old sexp)
> (subst ‘a ‘b ’((b c) (b () d)))
(if (symbol? sexp)
((a c) (a () d))
(if (eqv? sexp old) new sexp)
(subst new old sexp))))
Follow the Grammar
 Write one procedure for each nonterminal in the
grammar. The procedure will be responsible for handling the
data corresponding to that nonterminal, and nothing else.

 In each procedure, write one alternative for each


production corresponding to that nonterminal. You may need
additional case structure, but this will get you started. For
each nonterminal that appears in the right-hand side, write a
recursive call to the procedure for that nonterminal.

You might also like