Initial import.
This commit is contained in:
commit
36ed6df77f
|
@ -0,0 +1,12 @@
|
||||||
|
SANDBOX
|
||||||
|
=======
|
||||||
|
|
||||||
|
This is a repository of various repositories for learning or exploring
|
||||||
|
topics.
|
||||||
|
|
||||||
|
Projects
|
||||||
|
--------
|
||||||
|
|
||||||
|
+ ``lpn/``: `Learn Prolog Now <http://lpn.swi-prolog.org/>`_
|
||||||
|
+ ``uc/``: `Understanding Computation <http://computationbook.com/>`_
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
%% Exercise 2.4: Here are six Italian words:
|
||||||
|
%%
|
||||||
|
%% - astante
|
||||||
|
%% - astoria
|
||||||
|
%% - baratto
|
||||||
|
%% - cobalto
|
||||||
|
%% - pistola
|
||||||
|
%% - statale
|
||||||
|
%%
|
||||||
|
%% They are to be arranged, crossword puzzle fashion, in the following grid:
|
||||||
|
%%
|
||||||
|
%% V1 V2 V3
|
||||||
|
%% . . .
|
||||||
|
%% H1 . 1 . 4 . 7 .
|
||||||
|
%% . . .
|
||||||
|
%% H2 . 2 . 5 . 8 .
|
||||||
|
%% . . .
|
||||||
|
%% H3 . 3 . 6 . 9 .
|
||||||
|
%% . . .
|
||||||
|
%%
|
||||||
|
%% The following knowledge base represents a lexicon containing these words:
|
||||||
|
|
||||||
|
word(astante, a,s,t,a,n,t,e).
|
||||||
|
word(astoria, a,s,t,o,r,i,a).
|
||||||
|
word(baratto, b,a,r,a,t,t,o).
|
||||||
|
word(cobalto, c,o,b,a,l,t,o).
|
||||||
|
word(pistola, p,i,s,t,o,l,a).
|
||||||
|
word(statale, s,t,a,t,a,l,e).
|
||||||
|
|
||||||
|
%% Write a predicate crossword/6 that tells us how to fill in the
|
||||||
|
%% grid. The first three arguments should be the vertical words from
|
||||||
|
%% left to right, and the last three arguments the horizontal words
|
||||||
|
%% from top to bottom.
|
||||||
|
|
||||||
|
crossword(V1, V2, V3, H1, H2, H3) :-
|
||||||
|
word(V1, _, _1, _, _2, _, _3, _),
|
||||||
|
word(V2, _, _4, _, _5, _, _6, _),
|
||||||
|
word(V3, _, _7, _, _8, _, _9, _),
|
||||||
|
word(H1, _, _1, _, _4, _, _7, _),
|
||||||
|
word(H2, _, _2, _, _5, _, _8, _),
|
||||||
|
word(H3, _, _3, _, _6, _, _9, _),
|
||||||
|
V1 \= V2, V1 \= V3, V1 \= H1, V1 \= H2, V1 \= H3,
|
||||||
|
V2 \= V3, V2 \= H1, V2 \= H2, V2 \= H3,
|
||||||
|
V3 \= H1, V3 \= H2, V3 \= H3,
|
||||||
|
H1 \= H2, H1 \= H3, H2 \= H3.
|
||||||
|
|
||||||
|
%% NB: execute the following query to find out the correct arrangement.
|
||||||
|
%% crossword(A, B, C, D, E, F).
|
||||||
|
|
||||||
|
%% $ swipl -q
|
||||||
|
%% 1 ?- [italiano].
|
||||||
|
%% true.
|
||||||
|
%%
|
||||||
|
%% 2 ?- crossword(A, B, C, D, E, F).
|
||||||
|
%% A = astante,
|
||||||
|
%% B = cobalto,
|
||||||
|
%% C = pistola,
|
||||||
|
%% D = astoria,
|
||||||
|
%% E = baratto,
|
||||||
|
%% F = statale ;
|
||||||
|
%% A = astoria,
|
||||||
|
%% B = baratto,
|
||||||
|
%% C = statale,
|
||||||
|
%% D = astante,
|
||||||
|
%% E = cobalto,
|
||||||
|
%% F = pistola ;
|
||||||
|
%% false.
|
||||||
|
|
||||||
|
%% Note that there are two solutions; these are mirrors of each other
|
||||||
|
%% with the vertical words substituted for the horizontal words.
|
|
@ -0,0 +1,8 @@
|
||||||
|
is_digesting(X,Y) :- just_ate(X,Y).
|
||||||
|
is_digesting(X,Y) :-
|
||||||
|
just_ate(X,Z),
|
||||||
|
is_digesting(Z,Y).
|
||||||
|
|
||||||
|
just_ate(mosquito,blood(john)).
|
||||||
|
just_ate(frog,mosquito).
|
||||||
|
just_ate(stork,frog).
|
|
@ -0,0 +1,5 @@
|
||||||
|
woman(mia).
|
||||||
|
woman(jody).
|
||||||
|
woman(yolanda).
|
||||||
|
playsAirGuitar(jody).
|
||||||
|
party.
|
|
@ -0,0 +1,6 @@
|
||||||
|
happy(yolanda).
|
||||||
|
listens2Music(mia).
|
||||||
|
listens2Music(yolanda):- happy(yolanda).
|
||||||
|
playsAirGuitar(mia):- listens2Music(mia).
|
||||||
|
playsAirGuitar(yolanda):- listens2Music(yolanda).
|
||||||
|
listens2Music(bruce).
|
|
@ -0,0 +1,9 @@
|
||||||
|
happy(vincent).
|
||||||
|
listens2Music(butch).
|
||||||
|
playsAirGuitar(vincent):-
|
||||||
|
listens2Music(vincent),
|
||||||
|
happy(vincent).
|
||||||
|
playsAirGuitar(butch):-
|
||||||
|
happy(butch).
|
||||||
|
playsAirGuitar(butch):-
|
||||||
|
listens2Music(butch).
|
|
@ -0,0 +1,8 @@
|
||||||
|
woman(mia).
|
||||||
|
woman(jody).
|
||||||
|
woman(yolanda).
|
||||||
|
|
||||||
|
loves(vincent,mia).
|
||||||
|
loves(marsellus,mia).
|
||||||
|
loves(pumpkin,honey_bunny).
|
||||||
|
loves(honey_bunny,pumpkin).
|
|
@ -0,0 +1,11 @@
|
||||||
|
loves(vincent,mia).
|
||||||
|
loves(marsellus,mia).
|
||||||
|
loves(pumpkin,honey_bunny).
|
||||||
|
loves(honey_bunny,pumpkin).
|
||||||
|
|
||||||
|
/**
|
||||||
|
* original definition:
|
||||||
|
* jealous(X,Y):- loves(X,Z), loves(Y,Z).
|
||||||
|
*/
|
||||||
|
|
||||||
|
jealous(X,Y):- loves(X,Z), loves(Y,Z), X \= Y.
|
|
@ -0,0 +1,13 @@
|
||||||
|
word(determiner,a).
|
||||||
|
word(determiner,every).
|
||||||
|
word(noun,criminal).
|
||||||
|
word(noun,'big kahuna burger').
|
||||||
|
word(verb,eats).
|
||||||
|
word(verb,likes).
|
||||||
|
|
||||||
|
sentence(Word1,Word2,Word3,Word4,Word5):-
|
||||||
|
word(determiner,Word1),
|
||||||
|
word(noun,Word2),
|
||||||
|
word(verb,Word3),
|
||||||
|
word(determiner,Word4),
|
||||||
|
word(noun,Word5).
|
|
@ -0,0 +1,2 @@
|
||||||
|
vertical(line(point(X,Y),point(X,Z))).
|
||||||
|
horizontal(line(point(X,Y),point(Z,Y))).
|
|
@ -0,0 +1,9 @@
|
||||||
|
f(a).
|
||||||
|
f(b).
|
||||||
|
|
||||||
|
g(a).
|
||||||
|
g(b).
|
||||||
|
|
||||||
|
h(b).
|
||||||
|
|
||||||
|
k(X) :- f(X), g(X), h(X).
|
|
@ -0,0 +1,3 @@
|
||||||
|
listensToMusic(X) :- happy(X).
|
||||||
|
playsAirGuitar(X) :- listensToMusic(X).
|
||||||
|
happy(a).
|
|
@ -0,0 +1,2 @@
|
||||||
|
This is the superproject where all my attempts at working through the
|
||||||
|
book "Understanding Computation" are.
|
|
@ -0,0 +1 @@
|
||||||
|
Lisp code supporting "Universal Computation".
|
|
@ -0,0 +1,114 @@
|
||||||
|
;;; # The Meaning of Programs
|
||||||
|
|
||||||
|
;;; What is computation? what a computer does.
|
||||||
|
|
||||||
|
;;; computation environment:
|
||||||
|
;;;
|
||||||
|
;;; * machine
|
||||||
|
;;; * language
|
||||||
|
;;; * program
|
||||||
|
;;;
|
||||||
|
;;; Fundamentally, programming is about ideas: a program is a snapshot of
|
||||||
|
;;; an idea, a codification of the mental structures of the programmer(s)
|
||||||
|
;;; involved.
|
||||||
|
;;;
|
||||||
|
;;; ## The Meaning of "Meaning"
|
||||||
|
;;;
|
||||||
|
;;; *semantics* is the connection between words and meanings: while "dog"
|
||||||
|
;;; is an arrangment of shapes on a page, an actual dog is a very separate
|
||||||
|
;;; things. Semantics relates concrete signifiers and abstract meanings,
|
||||||
|
;;; and attempts to study the fundamental nature of the abstract meanings.
|
||||||
|
;;;
|
||||||
|
;;; *Formal semantics* is the attempt at formalising the meanings of
|
||||||
|
;;; programmings, and using this formalisation to reason about
|
||||||
|
;;; languages. In order to specify a programming language, we need to
|
||||||
|
;;; define both its *syntax* (the representation) and its *semantics* (the
|
||||||
|
;;; meaning).
|
||||||
|
;;;
|
||||||
|
;;; Most languages lack a formal specification and opt to use a canonical
|
||||||
|
;;; reference implementation. An alternative is to write a prose
|
||||||
|
;;; specification, which is the approach of C++. A third approach is to
|
||||||
|
;;; mathematically specify the language such that automated mathematical
|
||||||
|
;;; analysis can be done.
|
||||||
|
;;;
|
||||||
|
;;; ### Syntax
|
||||||
|
;;;
|
||||||
|
;;; The language's syntax is what differentiates valid examples of code like
|
||||||
|
|
||||||
|
(defun y (x) (+ x 1))
|
||||||
|
|
||||||
|
;;; from nonsense like `$%EHI`. In general, a parser reads a string
|
||||||
|
;;; (like "(defun y (x) (+ x 1)") and turns it into an *abstract
|
||||||
|
;;; syntax tree*. Syntax is ultimately only concerned with the surface
|
||||||
|
;;; appearance of the program
|
||||||
|
|
||||||
|
;;; ### Operational Semantics
|
||||||
|
|
||||||
|
;;; A practical means of thinking about the meaning of a program is
|
||||||
|
;;; *what it does*. *operational semantics* defines rules for how
|
||||||
|
;;; programs run on some machine (often an *abstract machine*).
|
||||||
|
|
||||||
|
;;; ### Small-Step Semantics
|
||||||
|
;;;
|
||||||
|
;;; Let's imagine an abstract machine that evaluates by directly
|
||||||
|
;;; operating on the syntax, reducing it iteratively to bring about the
|
||||||
|
;;; final result.
|
||||||
|
;;;
|
||||||
|
;;; For example, to evaluate (1 * 2) + (3 * 4):
|
||||||
|
|
||||||
|
;;; 0. Compute the left-hand multiplication (1 * 2 -> 2), simplifying
|
||||||
|
;;; the expression to 2 + (3 * 4).
|
||||||
|
|
||||||
|
;;; 0. Compute the right-hand multiplication (3 * 14 -> 12),
|
||||||
|
;;; simplifying the expression to 2 + 12.
|
||||||
|
|
||||||
|
;;; 0. Carry out the addition, resulting in 14.
|
||||||
|
|
||||||
|
;;; We determine that 14 is the result because it cannot be simplified
|
||||||
|
;;; any further. It is a special type of algebraic expression (a
|
||||||
|
;;; *value*) with its own meaning.
|
||||||
|
|
||||||
|
;;; We can write down formal rules like these describing how to proceed
|
||||||
|
;;; with each small reduction step; these rules are written in a
|
||||||
|
;;; *metalanguage* (which is often mathematical notation).
|
||||||
|
|
||||||
|
;;; Let's explore the semantics of a toy language called SIMPLE. There
|
||||||
|
;;; is a formal mathematical language to this, but we'll use a
|
||||||
|
;;; programming language to make it more clear.
|
||||||
|
|
||||||
|
(defclass ast-node ()
|
||||||
|
()
|
||||||
|
(:documentation "The superclass of all AST nodes."))
|
||||||
|
|
||||||
|
(defclass ast-number (ast-node)
|
||||||
|
((value :initarg :value :accessor nvalue))
|
||||||
|
(:documentation "A discrete, irreducible value."))
|
||||||
|
|
||||||
|
(defclass ast-add (ast-node)
|
||||||
|
((left :initarg :left :accessor ast-left)
|
||||||
|
(right :initarg :right :accessor ast-right))
|
||||||
|
(:documentation "AST node that adds its arguments together."))
|
||||||
|
|
||||||
|
(defclass ast-mult (ast-node)
|
||||||
|
((left :initarg :left :accessor ast-left)
|
||||||
|
(right :initarg :right :accessor ast-right))
|
||||||
|
(:documentation "AST node that multiplies its arguments together."))
|
||||||
|
|
||||||
|
(defun make-node (&key (type :number) (values (list 0 0)))
|
||||||
|
(cond
|
||||||
|
((equal type :number) (make-instance 'ast-number :value (car values)))
|
||||||
|
((equal type :add) (make-instance 'ast-add :left (car values) :right (cadr values)))
|
||||||
|
((equal type :mult) (make-instance 'ast-mult :left (car values) :right (cadr values)))))
|
||||||
|
|
||||||
|
(make-node :type :add
|
||||||
|
:values (list (make-node :type :mult
|
||||||
|
:values (list (make-node :values (list 1))
|
||||||
|
(make-node :values (list 2))))
|
||||||
|
(make-node :type :mult
|
||||||
|
:values (list (make-node :values (list 3))
|
||||||
|
(make-node :values (list 4))))))
|
||||||
|
|
||||||
|
;;; We can use these to build an AST by hand:
|
||||||
|
|
||||||
|
;;; print Add(Multiply (Number 2) Multiply (Number 3))
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
;;;; package.lisp
|
||||||
|
|
||||||
|
(defpackage #:uc
|
||||||
|
(:use #:cl))
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
;;;; uc.asd
|
||||||
|
|
||||||
|
(asdf:defsystem #:uc
|
||||||
|
:serial t
|
||||||
|
:description "Describe uc here"
|
||||||
|
:author "Your Name <your.name@example.com>"
|
||||||
|
:license "Specify license here"
|
||||||
|
:components ((:file "package")
|
||||||
|
(:file "uc")
|
||||||
|
(:file "meaning")))
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
;;;; uc.lisp
|
||||||
|
|
||||||
|
(in-package #:uc)
|
||||||
|
|
||||||
|
;;; "uc" goes here. Hacks and glory await!
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
## understanding computation
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
-- # The Meaning of Programs
|
||||||
|
|
||||||
|
-- What is computation? what a computer does.
|
||||||
|
|
||||||
|
-- computation environment:
|
||||||
|
--
|
||||||
|
-- * machine
|
||||||
|
-- * language
|
||||||
|
-- * program
|
||||||
|
--
|
||||||
|
-- Fundamentally, programming is about ideas: a program is a snapshot of
|
||||||
|
-- an idea, a codification of the mental structures of the programmer(s)
|
||||||
|
-- involved.
|
||||||
|
--
|
||||||
|
-- ## The Meaning of "Meaning"
|
||||||
|
--
|
||||||
|
-- *semantics* is the connection between words and meanings: while "dog"
|
||||||
|
-- is an arrangment of shapes on a page, an actual dog is a very separate
|
||||||
|
-- things. Semantics relates concrete signifiers and abstract meanings,
|
||||||
|
-- and attempts to study the fundamental nature of the abstract meanings.
|
||||||
|
--
|
||||||
|
-- *Formal semantics* is the attempt at formalising the meanings of
|
||||||
|
-- programmings, and using this formalisation to reason about
|
||||||
|
-- languages. In order to specify a programming language, we need to
|
||||||
|
-- define both its *syntax* (the representation) and its *semantics* (the
|
||||||
|
-- meaning).
|
||||||
|
--
|
||||||
|
-- Most languages lack a formal specification and opt to use a canonical
|
||||||
|
-- reference implementation. An alternative is to write a prose
|
||||||
|
-- specification, which is the approach of C++. A third approach is to
|
||||||
|
-- mathematically specify the language such that automated mathematical
|
||||||
|
-- analysis can be done.
|
||||||
|
--
|
||||||
|
-- ### Syntax
|
||||||
|
--
|
||||||
|
-- The language's syntax is what differentiates valid examples of code like
|
||||||
|
|
||||||
|
y x = x + 1
|
||||||
|
|
||||||
|
-- from nonsense like `$%EHI`. In general, a parser reads a string
|
||||||
|
-- (like "y x = x + 1") and turns it into an /abstract syntax
|
||||||
|
-- tree/. Syntax is ultimately only concerned with the surface
|
||||||
|
-- appearance of the program
|
||||||
|
|
||||||
|
-- ### Operational Semantics
|
||||||
|
|
||||||
|
-- A practical means of thinking about the meaning of a program is
|
||||||
|
-- *what it does*. *operational semantics* defines rules for how
|
||||||
|
-- programs run on some machine (often an *abstract machine*).
|
||||||
|
|
||||||
|
-- ### Small-Step Semantics
|
||||||
|
--
|
||||||
|
-- Let's imagine an abstract machine that evaluates by directly
|
||||||
|
-- operating on the syntax, reducing it iteratively to bring about the
|
||||||
|
-- final result.
|
||||||
|
--
|
||||||
|
-- For example, to evaluate (1 * 2) + (3 * 4):
|
||||||
|
|
||||||
|
-- 0. Compute the left-hand multiplication (1 * 2 -> 2), simplifying
|
||||||
|
-- the expression to 2 + (3 * 4).
|
||||||
|
|
||||||
|
-- 0. Compute the right-hand multiplication (3 * 14 -> 12),
|
||||||
|
-- simplifying the expression to 2 + 12.
|
||||||
|
|
||||||
|
-- 0. Carry out the addition, resulting in 14.
|
||||||
|
|
||||||
|
-- We determine that 14 is the result because it cannot be simplified
|
||||||
|
-- any further. It is a special type of algebraic expression (a
|
||||||
|
-- *value*) with its own meaning.
|
||||||
|
|
||||||
|
-- We can write down formal rules like these describing how to proceed
|
||||||
|
-- with each small reduction step; these rules are written in a
|
||||||
|
-- *metalanguage* (which is often mathematical notation).
|
||||||
|
|
||||||
|
-- Let's explore the semantics of a toy language called SIMPLE. There
|
||||||
|
-- is a formal mathematical language to this, but we'll use a
|
||||||
|
-- programming language to make it more clear.
|
||||||
|
|
||||||
|
class AST a where
|
||||||
|
reduce :: a -> Number
|
||||||
|
reducible :: a -> Bool
|
||||||
|
|
||||||
|
data Number = Number { value :: Integer } deriving (Show)
|
||||||
|
|
||||||
|
instance AST Number where
|
||||||
|
reduce (Number value) = (Number value)
|
||||||
|
reducible (Number _) = False
|
||||||
|
|
||||||
|
data Add = Add { leftAdd :: Number
|
||||||
|
, rightAdd :: Number
|
||||||
|
} deriving (Show)
|
||||||
|
|
||||||
|
instance AST Add where
|
||||||
|
reduce (Add x y) = Number (value x + value y)
|
||||||
|
reducible (Add _ _) = True
|
||||||
|
|
||||||
|
data Multiply = Multiply { leftMult :: Number
|
||||||
|
,rightMult :: Number
|
||||||
|
} deriving (Show)
|
||||||
|
|
||||||
|
-- We can use these to build an AST by hand:
|
||||||
|
|
||||||
|
-- print Add(Multiply (Number 2) Multiply (Number 3))
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
-- # The Meaning of Programs
|
||||||
|
|
||||||
|
-- What is computation? what a computer does.
|
||||||
|
|
||||||
|
-- computation environment:
|
||||||
|
-- * machine
|
||||||
|
-- * language
|
||||||
|
-- * program
|
||||||
|
--
|
||||||
|
-- Fundamentally, programming is about ideas: a program is a snapshot of
|
||||||
|
-- an idea, a codification of the mental structures of the programmer(s)
|
||||||
|
-- involved.
|
||||||
|
--
|
||||||
|
-- ## The Meaning of "Meaning"
|
||||||
|
--
|
||||||
|
-- /semantics/ is the connection between words and meanings: while "dog"
|
||||||
|
-- is an arrangment of shapes on a page, an actual dog is a very separate
|
||||||
|
-- things. Semantics relates concrete signifiers and abstract meanings,
|
||||||
|
-- and attempts to study the fundamental nature of the abstract meanings.
|
||||||
|
--
|
||||||
|
-- *Formal semantics* is the attempt at formalising the meanings of
|
||||||
|
-- programmings, and using this formalisation to reason about
|
||||||
|
-- languages. In order to specify a programming language, we need to
|
||||||
|
-- define both its *syntax* (the representation) and its *semantics* (the
|
||||||
|
-- meaning).
|
||||||
|
--
|
||||||
|
-- Most languages lack a formal specification and opt to use a canonical
|
||||||
|
-- reference implementation. An alternative is to write a prose
|
||||||
|
-- specification, which is the approach of C++. A third approach is to
|
||||||
|
-- mathematically specify the language such that automated mathematical
|
||||||
|
-- analysis can be done.
|
||||||
|
--
|
||||||
|
-- ### Syntax
|
||||||
|
--
|
||||||
|
-- The language's syntax is what differentiates valid examples of code like
|
||||||
|
|
||||||
|
y x = x + 1
|
||||||
|
|
||||||
|
-- from nonsense like `$%EHI`. In general, a parser reads a string
|
||||||
|
-- (like "y x = x + 1") and turns it into an /abstract syntax
|
||||||
|
-- tree/. Syntax is ultimately only concerned with the surface
|
||||||
|
-- appearance of the program
|
||||||
|
|
||||||
|
-- ### Operational Semantics
|
||||||
|
|
||||||
|
-- A practical means of thinking about the meaning of a program is
|
||||||
|
-- *what it does*.
|
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
What is computation? what a computer does.
|
||||||
|
|
||||||
|
computation environment:
|
||||||
|
|
||||||
|
* machine
|
||||||
|
|
||||||
|
* language
|
||||||
|
|
||||||
|
* program
|
||||||
|
|
||||||
|
Fundamentally, programming is about ideas: a program is a snapshot of
|
||||||
|
an idea, a codification of the mental structures of the programmer(s)
|
||||||
|
involved.
|
||||||
|
|
||||||
|
== The Meaning of "Meaning"
|
||||||
|
|
||||||
|
/semantics/ is the connection between words and meanings: while "dog"
|
||||||
|
is an arrangment of shapes on a page, an actual dog is a very separate
|
||||||
|
things. Semantics relates concrete signifiers and abstract meanings,
|
||||||
|
and attempts to study the fundamental nature of the abstract meanings.
|
||||||
|
|
||||||
|
_Formal semantics_ is the attempt at formalising the meanings of
|
||||||
|
programmings, and using this formalisation to reason about
|
||||||
|
languages. In order to specify a programming language, we need to
|
||||||
|
define both its /syntax/ (the representation) and its /semantics/ (the
|
||||||
|
meaning).
|
||||||
|
|
||||||
|
Most languages lack a formal specification and opt to use a canonical
|
||||||
|
reference implementation. An alternative is to write a prose
|
||||||
|
specification, which is the approach of C++. A third approach is to
|
||||||
|
mathematically specify the language such that automated mathematical
|
||||||
|
analysis can be done.
|
||||||
|
|
||||||
|
=== Syntax
|
||||||
|
|
||||||
|
The language's syntax is what differentiates valid examples of code like
|
||||||
|
|
||||||
|
> y x = x + 1
|
||||||
|
|
||||||
|
from nonsense like `$%EHI`. In general, a parser reads a string (like
|
||||||
|
"y x = x + 1") and turns it into an /abstract syntax tree/. Syntax is ultimately only concerned with the surface appearance of the program
|
||||||
|
|
||||||
|
=== Operational Semantics
|
||||||
|
|
||||||
|
A practical means of thinking about the meaning of a program is /what it does/.
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Revision history for uc
|
||||||
|
|
||||||
|
## 0.1.0.0 -- YYYY-mm-dd
|
||||||
|
|
||||||
|
* First version. Released on an unsuspecting world.
|
|
@ -0,0 +1,20 @@
|
||||||
|
Copyright (c) 2016 Kyle Isom
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,2 @@
|
||||||
|
import Distribution.Simple
|
||||||
|
main = defaultMain
|
Binary file not shown.
After Width: | Height: | Size: 526 KiB |
|
@ -0,0 +1,228 @@
|
||||||
|
Chapter 2: The Meaning of Programs
|
||||||
|
==================================
|
||||||
|
|
||||||
|
> module Meaning where
|
||||||
|
|
||||||
|
Programming is about ideas, not about the programs themselves;
|
||||||
|
they're manifestations (sometimes even physical) of someone's ideas;
|
||||||
|
there must be some *raison d'être* for program to be written. That
|
||||||
|
reason can be to scratch an itch, but some motivation needs to drive
|
||||||
|
the program.
|
||||||
|
|
||||||
|
Linguistics has a field called *semantics*, which "is the study of
|
||||||
|
the connection between words and their meanings;" computer science
|
||||||
|
has *formal semantics*, which deals with specifying these connections
|
||||||
|
mathemtically (more or less). Specifying a programming language
|
||||||
|
requires both a syntax (*how does the program look*?) and semantics
|
||||||
|
(*what does the program mean*?). Funny enough, many (most?) PL's
|
||||||
|
don't have some canonical formal specification, relying on
|
||||||
|
"specification by implementation."
|
||||||
|
|
||||||
|
|
||||||
|
Syntax
|
||||||
|
------
|
||||||
|
|
||||||
|
Remember: syntax = how does the program look?
|
||||||
|
|
||||||
|
Programming is currently done largely as text files, which are
|
||||||
|
really just long strings of characters where newlines give the
|
||||||
|
appearance of some structure. We fead this string into a parser of
|
||||||
|
some sort, which knows the language's syntax rules. The parser takes
|
||||||
|
the string and converts into an *abstract syntax tree*, which is
|
||||||
|
the computer's representation of the program in memory. **N.B.**:
|
||||||
|
parsers are covered later.
|
||||||
|
|
||||||
|
Syntax provides a mechanism for the meaning of a program to be
|
||||||
|
expressed, but it doesn't have any deeper meaning. The connection
|
||||||
|
is entirely arbitrary, though there are common patterns that have
|
||||||
|
arisen (c.f. the C-style of langauges).
|
||||||
|
|
||||||
|
|
||||||
|
Operational Semantics
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
"The most practical way to think about the meaning of a program is
|
||||||
|
*what it does*." That is, what happens when it runs? I really liked
|
||||||
|
how Tom phrased it: "How do different constructs in the programming
|
||||||
|
language behave at run time, and what effect do they have when
|
||||||
|
they're plugged together to make larger programs?"
|
||||||
|
|
||||||
|
*Operational semantics* defines rules for how programs execute,
|
||||||
|
typically on an *abstract machine*, allowing for more precise
|
||||||
|
specifications of a language's behaviour.
|
||||||
|
|
||||||
|
|
||||||
|
Small-Step Semantics
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
How do we go about designing an abstract machine? A first step is
|
||||||
|
to think about how a program that works by reduction on the syntax.
|
||||||
|
For example, evaluating (1 × 2) + (3 × 4):
|
||||||
|
|
||||||
|
1. First, the leftmost expression is reduced: × is applied to 1
|
||||||
|
and 2. This leaves us with 2 + (3 × 4).
|
||||||
|
2. The rightmost expression is reduced: × is applied to 3
|
||||||
|
and 4. This leaves us with 2 + 12.
|
||||||
|
3. Finally, + is applied to 2 and 12, yielding 14.
|
||||||
|
4. 14 can't be reduced any further, so this is taken as the result
|
||||||
|
of the expression. This is a *value*, which has a standalone
|
||||||
|
meaning.
|
||||||
|
|
||||||
|
The rules for these reductions need to be codified in their own
|
||||||
|
*metalanguage*. To explore the semantics of a very simple programming
|
||||||
|
language called SIMPLE.
|
||||||
|
|
||||||
|
[ insert meaning_simple_semantics.png here ]
|
||||||
|
|
||||||
|
These are *inference rules* defining a *reduction relation* on
|
||||||
|
SIMPLE ASTs. "Practically speaking, it's a bunch of weird symbols
|
||||||
|
that don't say anything intelligible about the meaning of computer
|
||||||
|
programs." Time to dive into an implementation!
|
||||||
|
|
||||||
|
Tom is careful to note that this isn't an attempt at specification
|
||||||
|
by implementation; it's making the description more approachable
|
||||||
|
for readers without a mathematical background.
|
||||||
|
|
||||||
|
|
||||||
|
Expressions
|
||||||
|
-----------
|
||||||
|
|
||||||
|
We can start by defining some types for the different elements ofthe AST.
|
||||||
|
|
||||||
|
> data Element = Number Int |
|
||||||
|
> Boolean Bool |
|
||||||
|
> Add Element Element |
|
||||||
|
> Multiply Element Element |
|
||||||
|
> LessThan Element Element |
|
||||||
|
> Equals Element Element |
|
||||||
|
> GreaterThan Element Element
|
||||||
|
|
||||||
|
For convenience, we'll override show. In the book, SIMPLE ASTs are
|
||||||
|
displayed inside «».
|
||||||
|
|
||||||
|
> -- strElement returns the string representation of an AST element.
|
||||||
|
> strElement :: Element -> String
|
||||||
|
> strElement (Number n) = show n
|
||||||
|
> strElement (Boolean b) = show b
|
||||||
|
> strElement (Add a b) = (strElement a) ++ " + " ++ (strElement b)
|
||||||
|
> strElement (Multiply a b) = (strElement a) ++ " × " ++ (strElement b)
|
||||||
|
|
||||||
|
> -- showElement implements show for Element.
|
||||||
|
> showElement :: Element -> String
|
||||||
|
> showElement e = "«" ++ (strElement e) ++ "»"
|
||||||
|
> instance Show Element where show = showElement
|
||||||
|
|
||||||
|
These elements can be strung together to hand-build an AST:
|
||||||
|
|
||||||
|
> anExpression = Add (Multiply (Number 1) (Number 2))
|
||||||
|
> (Multiply (Number 3) (Number 4))
|
||||||
|
|
||||||
|
This *should* display as
|
||||||
|
|
||||||
|
```
|
||||||
|
Ok, modules loaded: Meaning.
|
||||||
|
*Meaning>
|
||||||
|
*Meaning> anExpression
|
||||||
|
«1 × 2 + 3 × 4»
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that this doesn't take into account operator precedence, so
|
||||||
|
`anExpression` is the same as `otherExpression` defined below:
|
||||||
|
|
||||||
|
> otherExpression = Multiply (Number 1)
|
||||||
|
> (Multiply (Add (Number 2) (Number 3))
|
||||||
|
> (Number 4))
|
||||||
|
|
||||||
|
With proper precendence, this should be `1 * (2 + 3) * 4`, but note
|
||||||
|
|
||||||
|
```
|
||||||
|
*Meaning> anExpression
|
||||||
|
«1 × 2 + 3 × 4»
|
||||||
|
*Meaning> otherExpression
|
||||||
|
«1 × 2 + 3 × 4»
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a problem, but it's not relevant to the discussion of the
|
||||||
|
semantics of SIMPLE.
|
||||||
|
|
||||||
|
Now we need to implement a reducer. First, let's determine if an
|
||||||
|
expression *can* be reduced:
|
||||||
|
|
||||||
|
> -- reducible returns true if the expression is reducible.
|
||||||
|
> reducible :: Element -> Bool
|
||||||
|
> reducible (Number _) = False
|
||||||
|
> reducible _ = True
|
||||||
|
|
||||||
|
> -- reduce reduces the expression.
|
||||||
|
> reduce :: Element -> Element
|
||||||
|
> reduce n@(Number _) = n
|
||||||
|
> reduce (Add (Number a) (Number b)) = Number (a + b)
|
||||||
|
> reduce (Add a b) = if (reducible a)
|
||||||
|
> then (Add (reduce a) b)
|
||||||
|
> else (Add a (reduce b))
|
||||||
|
> reduce (Multiply (Number a) (Number b)) = Number (a * b)
|
||||||
|
> reduce (Multiply a b) = if (reducible a)
|
||||||
|
> then (Multiply (reduce a) b)
|
||||||
|
> else (Multiply a (reduce b))
|
||||||
|
|
||||||
|
Using `reduce` right now means repeatedly running `reduce` over
|
||||||
|
functions:
|
||||||
|
|
||||||
|
```
|
||||||
|
*Meaning> reduce anExpression
|
||||||
|
«2 + 3 × 4»
|
||||||
|
*Meaning> reduce (reduce anExpression)
|
||||||
|
«2 + 12»
|
||||||
|
*Meaning> reduce (reduce (reduce anExpression))
|
||||||
|
«14»
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that `reduce` returns different expressions for `anExpression`
|
||||||
|
and `otherExpression`, which demonstrates that the string display
|
||||||
|
issue is tangential to our semantics:
|
||||||
|
|
||||||
|
```
|
||||||
|
*Meaning> reduce anExpression
|
||||||
|
«2 + 3 × 4»
|
||||||
|
*Meaning> reduce otherExpression
|
||||||
|
«1 × 5 × 4»
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's abstract this into a machine; note that this won't work quite
|
||||||
|
like the Ruby examples in the book, as we can't really keep state
|
||||||
|
in Haskell.
|
||||||
|
|
||||||
|
> -- Machine abstracts the SIMPLE VM.
|
||||||
|
> data Machine = Machine Element
|
||||||
|
> instance Show Machine where
|
||||||
|
> show (Machine e) = "EXP ← " ++ (show e)
|
||||||
|
|
||||||
|
We can define two functions on it: `step` and `run`:
|
||||||
|
|
||||||
|
> -- step runs a single reduction.
|
||||||
|
> step :: Machine -> Machine
|
||||||
|
> step (Machine e) = Machine (reduce e)
|
||||||
|
|
||||||
|
> -- run keeps calling step until a non-reducible expression is
|
||||||
|
> -- found.
|
||||||
|
> run :: Machine -> IO Machine
|
||||||
|
> run m@(Machine e) = do
|
||||||
|
> putStrLn (show m)
|
||||||
|
> if (reducible e)
|
||||||
|
> then run (step m)
|
||||||
|
> else return (Machine e)
|
||||||
|
|
||||||
|
Let's try this with `anExpression`:
|
||||||
|
|
||||||
|
> anMachine = Machine anExpression
|
||||||
|
|
||||||
|
```
|
||||||
|
*Meaning> step anMachine
|
||||||
|
EXP ← «2 + 3 × 4»
|
||||||
|
*Meaning> run anMachine
|
||||||
|
EXP ← «1 × 2 + 3 × 4»
|
||||||
|
EXP ← «2 + 3 × 4»
|
||||||
|
EXP ← «2 + 12»
|
||||||
|
EXP ← «14»
|
||||||
|
EXP ← «14»
|
||||||
|
```
|
|
@ -0,0 +1,67 @@
|
||||||
|
-- Initial uc.cabal generated by cabal init. For further documentation,
|
||||||
|
-- see http://haskell.org/cabal/users-guide/
|
||||||
|
|
||||||
|
-- The name of the package.
|
||||||
|
name: uc
|
||||||
|
|
||||||
|
-- The package version. See the Haskell package versioning policy (PVP)
|
||||||
|
-- for standards guiding when and how versions should be incremented.
|
||||||
|
-- https://wiki.haskell.org/Package_versioning_policy
|
||||||
|
-- PVP summary: +-+------- breaking API changes
|
||||||
|
-- | | +----- non-breaking API additions
|
||||||
|
-- | | | +--- code changes with no API change
|
||||||
|
version: 0.1.0.0
|
||||||
|
|
||||||
|
-- A short (one-line) description of the package.
|
||||||
|
synopsis: Literate Haskell explorations from the book 'Understanding Computation'.
|
||||||
|
|
||||||
|
-- A longer description of the package.
|
||||||
|
-- description:
|
||||||
|
|
||||||
|
-- The license under which the package is released.
|
||||||
|
license: MIT
|
||||||
|
|
||||||
|
-- The file containing the license text.
|
||||||
|
license-file: LICENSE
|
||||||
|
|
||||||
|
-- The package author(s).
|
||||||
|
author: Kyle Isom
|
||||||
|
|
||||||
|
-- An email address to which users can send suggestions, bug reports, and
|
||||||
|
-- patches.
|
||||||
|
maintainer: kyle@imap.cc
|
||||||
|
|
||||||
|
-- A copyright notice.
|
||||||
|
-- copyright:
|
||||||
|
|
||||||
|
category: Meta
|
||||||
|
|
||||||
|
build-type: Simple
|
||||||
|
|
||||||
|
-- Extra files to be distributed with the package, such as examples or a
|
||||||
|
-- README.
|
||||||
|
extra-source-files: ChangeLog.md
|
||||||
|
|
||||||
|
-- Constraint on the version of Cabal needed to build this package.
|
||||||
|
cabal-version: >=1.10
|
||||||
|
|
||||||
|
|
||||||
|
library
|
||||||
|
-- Modules exported by the library.
|
||||||
|
-- exposed-modules:
|
||||||
|
|
||||||
|
-- Modules included in this library but not exported.
|
||||||
|
-- other-modules:
|
||||||
|
|
||||||
|
-- LANGUAGE extensions used by modules in this package.
|
||||||
|
-- other-extensions:
|
||||||
|
|
||||||
|
-- Other library packages from which modules are imported.
|
||||||
|
build-depends: base >=4.9 && <4.10
|
||||||
|
|
||||||
|
-- Directories containing source files.
|
||||||
|
hs-source-dirs: src
|
||||||
|
|
||||||
|
-- Base language which the package is written in.
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
# # The Meaning of Programs
|
||||||
|
# Let's define a simple *AST*, with three basic members. An AST node can
|
||||||
|
# be reducible, like the + in (2 + 2), or not-reducible, like the
|
||||||
|
# number 2. We'll also reduce from left to right.
|
||||||
|
class Number:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = int(value)
|
||||||
|
def __repr__(self):
|
||||||
|
return "#" + str(self.value)
|
||||||
|
def is_reducible(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
class Add:
|
||||||
|
def __init__(self, l, r):
|
||||||
|
self.left = l
|
||||||
|
self.right = r
|
||||||
|
def __repr__(self):
|
||||||
|
return repr(self.left) + " + " + repr(self.right)
|
||||||
|
def is_reducible(self):
|
||||||
|
return True
|
||||||
|
def reduce(self, env):
|
||||||
|
if self.left.is_reducible():
|
||||||
|
return Add(self.left.reduce(env), self.right)
|
||||||
|
elif self.right.is_reducible():
|
||||||
|
return Add(self.left, self.right.reduce(env))
|
||||||
|
else:
|
||||||
|
return Number(self.left.value + self.right.value)
|
||||||
|
|
||||||
|
class Mult:
|
||||||
|
def __init__(self, l, r):
|
||||||
|
self.left = l
|
||||||
|
self.right = r
|
||||||
|
def __repr__(self):
|
||||||
|
return repr(self.left) + " * " + repr(self.right)
|
||||||
|
def is_reducible(self):
|
||||||
|
return True
|
||||||
|
def reduce(self, env):
|
||||||
|
if self.left.is_reducible():
|
||||||
|
return Mult(self.left.reduce(env), self.right)
|
||||||
|
elif self.right.is_reducible():
|
||||||
|
return Mult(self.left, self.right.reduce(env))
|
||||||
|
else:
|
||||||
|
return Number(self.left.value * self.right.value)
|
||||||
|
|
||||||
|
ast1 = Add(Mult(Number(1), Number(2)),
|
||||||
|
Mult(Number(3), Number(4)))
|
||||||
|
|
||||||
|
# It would be nice to have a machine that could run these, so we don't
|
||||||
|
# have to run them by hand.
|
||||||
|
|
||||||
|
class Machine:
|
||||||
|
def __init__(self, expr, env):
|
||||||
|
self.expr = expr
|
||||||
|
self.env = env
|
||||||
|
self.iters = 0
|
||||||
|
|
||||||
|
def step(self):
|
||||||
|
self.iters += 1
|
||||||
|
self.expr = self.expr.reduce(self.env)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while self.expr.is_reducible():
|
||||||
|
print self
|
||||||
|
self.step()
|
||||||
|
print "execution complete in ", self.iters, " steps."
|
||||||
|
return self.expr
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "(" + str(self.iters) + ") " + repr(self.expr) + "\n" + repr(self.env)
|
||||||
|
|
||||||
|
class Boolean:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self.value).lower()
|
||||||
|
def is_reducible(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
class LessThan:
|
||||||
|
def __init__(self, l, r):
|
||||||
|
self.left = l
|
||||||
|
self.right = r
|
||||||
|
def __repr__(self):
|
||||||
|
return repr(self.left) + " < " + repr(self.right)
|
||||||
|
def is_reducible(self):
|
||||||
|
return True
|
||||||
|
def reduce(self, env):
|
||||||
|
if self.left.is_reducible():
|
||||||
|
return LessThan(self.left.reduce(env), self.right)
|
||||||
|
elif self.right.is_reducible():
|
||||||
|
return LessThan(self.left, self.right.reduce(env))
|
||||||
|
else:
|
||||||
|
return Boolean(self.left.value < self.right.value)
|
||||||
|
|
||||||
|
ast2 = LessThan(Number(5), Add(Number(2), Number(2)))
|
||||||
|
ast2b = LessThan(Add(Number(2), Number(2)), Number(5))
|
||||||
|
|
||||||
|
class Variable:
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
def __repr__(self):
|
||||||
|
return "$" + self.name
|
||||||
|
def is_reducible(self):
|
||||||
|
return True
|
||||||
|
def reduce(self, env):
|
||||||
|
return env[self.name]
|
||||||
|
|
||||||
|
ast3 = Add(Variable('x'), Variable('y'))
|
||||||
|
env3 = {'x': Number(3), 'y': Number(4)}
|
||||||
|
m3 = lambda : Machine(ast3, env3)
|
||||||
|
|
||||||
|
class Nop:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
def __repr__(self):
|
||||||
|
return "@NOP"
|
||||||
|
def eq(self, st):
|
||||||
|
return st.instanceof(Nop)
|
||||||
|
def is_reducible(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
class Assign:
|
||||||
|
def __init__(self, name, expr):
|
||||||
|
self.name = name
|
||||||
|
self.expr = expr
|
||||||
|
def __repr__(self):
|
||||||
|
return self.name + " = " + repr(self.expr)
|
||||||
|
def is_reducible(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def reduce(self, env):
|
||||||
|
if self.expr.is_reducible():
|
||||||
|
return Assign(self.name, self.expr.reduce(env)), env.copy()
|
||||||
|
else:
|
||||||
|
env[self.name] = self.expr
|
||||||
|
return Nop(), env.copy()
|
||||||
|
|
||||||
|
stmt4 = Assign("x", Add(Variable("x"), Number(1)))
|
||||||
|
env4 = {"x": Number(2)}
|
||||||
|
|
||||||
|
class Machine2:
|
||||||
|
def __init__(self, stmt, env):
|
||||||
|
self.stmt = stmt
|
||||||
|
self.env = env
|
||||||
|
self.iters = 0
|
||||||
|
def __repr__(self):
|
||||||
|
return "(" + str(self.iters) + ") " + repr(self.stmt) + "\n" + repr(self.env)
|
||||||
|
def step(self):
|
||||||
|
self.iters += 1
|
||||||
|
self.stmt, self.env = self.stmt.reduce(self.env)
|
||||||
|
print self
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while self.stmt.is_reducible():
|
||||||
|
self.step()
|
||||||
|
print "execution complete in ", self.iters, " steps."
|
||||||
|
print self
|
||||||
|
|
||||||
|
stmt5 = Assign("x", Add(Variable("x"), Number(1)))
|
||||||
|
env5 = {"x": Number(2)}
|
||||||
|
m5 = lambda : Machine2(stmt5, env5)
|
||||||
|
|
||||||
|
class If:
|
||||||
|
def __init__(self, cond, cons, alt):
|
||||||
|
self.cond = cond
|
||||||
|
self.cons = cons
|
||||||
|
self.alt = alt
|
||||||
|
def __repr__(self):
|
||||||
|
s = "if |" + repr(self.cond) + "| then |" + repr(self.cons)
|
||||||
|
return s + "| else |" + repr(self.alt) + "|"
|
||||||
|
def is_reducible(self):
|
||||||
|
return True
|
||||||
|
def reduce(self, env):
|
||||||
|
if self.cond.is_reducible():
|
||||||
|
return If(self.cond.reduce(env), self.cons, self.alt), env.copy()
|
||||||
|
elif self.cond.value:
|
||||||
|
return self.cons, env.copy()
|
||||||
|
else:
|
||||||
|
return self.alt, env.copy()
|
||||||
|
|
||||||
|
stmt6 = If(Variable("x"), Assign("y", Number(1)), Assign("y", Number(2)))
|
||||||
|
env6 = {"x": Boolean(True)}
|
||||||
|
m6 = lambda : Machine2(stmt6, env6)
|
||||||
|
|
||||||
|
class Sequence:
|
||||||
|
def __init__(self, first, second):
|
||||||
|
self.first = first
|
||||||
|
self.second = second
|
||||||
|
def __repr__(self):
|
||||||
|
return repr(self.first) + ";" + repr(self.second)
|
||||||
|
def is_reducible(self):
|
||||||
|
return True
|
||||||
|
def reduce(self, env):
|
||||||
|
if isinstance(self.first, Nop):
|
||||||
|
return self.second, env.copy()
|
||||||
|
else:
|
||||||
|
first, env = self.first.reduce(env)
|
||||||
|
return Sequence(first, self.second), env.copy()
|
||||||
|
|
||||||
|
stmt7 = Sequence(Assign("x", Add(Number(1), Number(1))),
|
||||||
|
Assign("y", Add(Variable("x"), Number(3))))
|
||||||
|
env7 = {}
|
||||||
|
m7 = lambda : Machine2(stmt7, env7)
|
||||||
|
|
||||||
|
class While:
|
||||||
|
def __init__(self, cond, body):
|
||||||
|
self.cond = cond
|
||||||
|
self.body = body
|
||||||
|
def __repr__(self):
|
||||||
|
return "while |" + repr(self.cond) + "|:\n\t" + repr(self.body)
|
||||||
|
def is_reducible(self):
|
||||||
|
return True
|
||||||
|
def reduce(self, env):
|
||||||
|
return If(self.cond, Sequence(self.body, self), Nop()), env.copy()
|
||||||
|
|
||||||
|
stmt8 = While(LessThan(Variable("x"), Number(5)),
|
||||||
|
Assign("x", Mult(Variable("x"), Number(3))))
|
||||||
|
env8 = {"x": Number(1)}
|
||||||
|
m8 = lambda : Machine2(stmt8, env8)
|
Loading…
Reference in New Issue