E [[0]]s = (0,s) E [[1]]s = (1,s) E [[read]](m, i, o) = if (empty i) then error, else (hd i, (m, tl i, o)) E [[I]](m, i, o) = if m i = unbound then error, else (m I, (m, i, o)) E [[E1 + E2]]s = if (E [[E1]]s = (v1,s1) & E [[E2]]s1 = (v2,s2)) then (v1 + v2, s2) else error E [[fn x => E]]s = fun n in Nat. E [[E]](s[n/x]) E [[E1 (E2)]]s = E [[E1]]s (E [[E2]]s)Note difference in meaning of function here from that of operational semantics!
Define B: BoolExp -> [State -> [[Value x State] + {error}]] by:
B [[true]]s = (true,s) B [[false]]s = (false,s) B [[not B]]s = if B [[B]]s = (v,s') then (not v, s'), else error B [[E1 = E2]]s = if (E [[E1]]s = (v1,s1) & E [[E2]]s1 = (v2,s2)) then (v1 = v2, s2) else error
Define C : Command -> [State -> [State + {error}]] by:
C [[I := E]]s = if E [[E]]s = (v,(m,i,o)) then (m[v/I],i,o) else errorwhere m' = m[v/I] is identical to m except the value of I is v.
C [[output E]]s = if E [[E]]s = (v,(m,i,o)) then (m,i,v.o) else errorwhere v.o is the result of attaching v to the front of o.
C [[if E then C1 else C2]]s = if B [[B]]s = (v,s') then if v then C [[C1]]s' else C [[C2]]s' else error C [[while E do C]]s = if B [[B]]s = (v,s') then if v then if C [[C]]s' = s'' then C [[while E do C]]s'' else error else s' else error C [[C1; C2]]s = if C [[C1]]s = error then error else C [[C2]] ( C [[C1]]s)End Tiny
Notice that definition of while is a recursive definition.
Thus, if B [[B]] s = True and s' = C [[S]] s, then C[[while B do S]]s = C [[while B do S]]s'
Solution involves computing what is known as least fixed points.
Denotational semantics gained considerable popularity over last 15 years.
Many people consider denotational semantics as most appropriate for studying meaning of language independent of its implementation.
Good for looking at trade-offs between alternate forms of similar constructs.
Which is best?
No good answer, since have different uses.
Complementary definitions. Can be compared for consistency.
Programming language definitions usually still given in English. Formal definitions often too hard to understand or require too much sophistication. Gaining much more acceptance. Now relatively standard intro graduate course in CS curricula.
Some success at using formal semantics (either denotational or operational) to automate compiler construction (similar to use of formal grammars in automatic parser generation).
Semantic definitions have also proved to be useful in understanding new programming constructs.
What is logic programming? -
"A constructive proof that for every list L there is a corresponding sorted list S composed of the same elements as L yields an algorithm for sorting a list."
Philosophy is shared by others not working on "logic programming", e.g. Constable at Cornell, Martin-Löf in Sweden, Calculus of Constructions group in France. These groups want to extract (more traditional) program from constructive proofs.
Very-High-Level Languages - non-procedural
State what must be done, not how to do it. Idea is to separate logic from control. (Examples later)
Developed in 1972 by Alain Colmerauer in Marseilles.
Text has an excellent introduction to PROLOG. I will presume you have read it and concentrate on examples!
Often best to start out as thinking of Prolog in terms of language for working with a data base.
Three types of statements:
Facts (or hypotheses):
father(albert,jeffrey).Rules (or conditions):
grandparent(X,Z) :- parent(X,Y),parent(Y,Z).(read ":-" as "if")
Queries (or goals):
?-grandparent(X,jeffrey).
Should think of language as non-deterministic (or non-procedural). Looks for all answers satisfying predicate.
father(john,ralph). father(mary,ralph). father(ralph,bill). mother(john,sue). mother(mary,sue). mother(ralph,joan). male(john). male(ralph). male(bill). female(mary). female(sue). /* RULES */ is_mother(M):-mother(Y,M). parent(X,M):-mother(X,M). parent(X,F):-father(X,F). parents(X,M,F):-mother(X,M),father(X,F). sister(X,S):-female(S),parents(X,M,F),parents(S,M,F),S\=X. ancester(X,Y):-parent(X,Y). ancester(X,Y):-parent(X,Z),ancester(Z,Y). /***********************newsort.pro**************************/ /********************Selection Sort*******************/ sel_sort([],[]). sel_sort(L,[Small|R]) :- smallest(L,Small) , delete(Small,L,Rest) , sel_sort(Rest,R) . /* smallest(List, Small) results in Small being the smallest element in List. */ smallest([Small],Small) . smallest([H|T],Small) :- smallest(T,Small) , Small=<H. smallest([H|T],H). /* delete(Elt,List,Result) has Result as List after deleting Elt. */ delete(Elt,[],[]) . delete(Elt,[Elt|T],T) . delete(Elt,[H|T],[H|NuTail]) :- delete(Elt,T,NuTail) . /*******************Insertion Sort********************/ ins_sort([],[]) . ins_sort([H|T],Sorted) :- ins_sort(T,Rest), insert(H,Rest,Sorted) . /* insert(Elt,List,Result) - if List is sorted, Result is obtained by putting Elt where it fits in order in List. */ insert(Elt,[],[Elt]) . insert(Elt,[H|T],[Elt,H|T]) :- (Elt=<H) . insert(Elt,[H|T],[H|Sorted]) :- insert(Elt,T,Sorted) . /* **********Quick Sort************** */ /* sep(List,Key,Less,More) separates the List into the set of elements less than or equal to Key (in Less) and those greater than or equal to Key (in More) */ sep([],Key,[],[]) . sep([H|T],Key,Less,[H|More]) :- (H>Key) , sep(T,Key,Less,More) . sep([H|T],Key,[H|Less],More) :- (H=<Key) , sep(T,Key,Less,More) . quick_sort([],[]) . quick_sort([H|T],Sorted) :- sep(T,H,Less,More) , quick_sort(Less,L_sorted) , quick_sort(More,M_sorted) , concat(L_sorted,[H|M_sorted],Sorted) . /* concat(First, Second, List) results in List = concatenation of First and Second. */ concat([],L,L) . concat([H|T],L,[H|C]) :- concat(T,L,C) . /************************************************ Can take advantage of reversibility since computing with relations rather than functions. ********************Permutations*******************/ append([],L,L) . append([H|T],L,[H|R]) :- append(T,L,R) . permute([],[]) . permute(L,[H|T]) :- append(V,[H|U],L) , /* V,U stand for the part of L before and after H */ append(V,U,W) , permute(W,T) . ***********************************************
Ex.
father(john,ralph). father(mary,ralph). father(ralph,bill). mother(john,sue). mother(mary,sue). mother(ralph,joan). /* RULES */ is_mother(M):-mother(Y,M). parent(X,M):-mother(X,M). parent(X,F):-father(X,F). ancester(X,Y):-parent(X,Y). ancester(X,Y):-parent(X,Z),ancester(Z,Y). ?-ancester(X,joan).backtracking
First succeeds with X = ralph
later w/X= john, mary
Usually in prefix, can force to be in infix or postfix and give precedence as well.
Ex. +, - ,*,/
2+3*5 abbreviates +(2,*(3,5))
operations are not evaluated
Better to think of operations as forming tags on values -
Relations
=, \=, <, >, =<, >= (note order of composite relations) are evaluated.
Ex. digit(N):- N>=0,N<10.
Example of using operations.
treesort
tree is either nil or is of form maketree(tree1,X,tree2).
Write program to do treesort! Very much like ML program.
Ex. area(L,W,A):-A is L*W.
Can only compute A from L,W - not reversible.