From 5f9633349c522c59bbe57f743af8b6d1aa132316 Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Thu, 18 Jan 2018 16:30:58 -0800 Subject: [PATCH] Add ch04, start working on ch05. --- lpn/ch01/notes.md | 2 +- lpn/ch02/notes.md | 2 +- lpn/ch03/notes.md | 2 +- lpn/ch04/exercises.pl | 60 +++++++++++++++++++++++++++++++++++ lpn/ch04/list.pl | 13 ++++++++ lpn/ch04/notes.md | 30 ++++++++++++++++++ lpn/ch04/practical.pl | 39 +++++++++++++++++++++++ lpn/ch05/arith.pl | 21 ++++++++++++ lpn/ch05/exercises.pl | 24 ++++++++++++++ lpn/ch05/notes.md | 74 +++++++++++++++++++++++++++++++++++++++++++ lpn/ch05/practical.pl | 54 +++++++++++++++++++++++++++++++ 11 files changed, 318 insertions(+), 3 deletions(-) create mode 100644 lpn/ch04/exercises.pl create mode 100644 lpn/ch04/list.pl create mode 100644 lpn/ch04/notes.md create mode 100644 lpn/ch04/practical.pl create mode 100644 lpn/ch05/arith.pl create mode 100644 lpn/ch05/exercises.pl create mode 100644 lpn/ch05/notes.md create mode 100644 lpn/ch05/practical.pl diff --git a/lpn/ch01/notes.md b/lpn/ch01/notes.md index 5cbf06f..38c4b9d 100644 --- a/lpn/ch01/notes.md +++ b/lpn/ch01/notes.md @@ -1,4 +1,4 @@ -## Some basic syntax +## Chapter 1: Some basic syntax ``` property(name). diff --git a/lpn/ch02/notes.md b/lpn/ch02/notes.md index 2739ecd..41ca6cd 100644 --- a/lpn/ch02/notes.md +++ b/lpn/ch02/notes.md @@ -1,4 +1,4 @@ -## Unification +## Chapter 2: Unification Two terms unify if they are 1. The same term diff --git a/lpn/ch03/notes.md b/lpn/ch03/notes.md index b1198e8..1413a9f 100644 --- a/lpn/ch03/notes.md +++ b/lpn/ch03/notes.md @@ -1,4 +1,4 @@ -## Recursion +## Chapter 3: Recursion Recursive definitions require that the recursive function isn't the first clause, ex: diff --git a/lpn/ch04/exercises.pl b/lpn/ch04/exercises.pl new file mode 100644 index 0000000..19abc28 --- /dev/null +++ b/lpn/ch04/exercises.pl @@ -0,0 +1,60 @@ +%% Exercises from chapter 4 +%% +%% Exercise 4.3 Write a predicate second(X,List) which checks whether X is the +%% second element of List . + +second(X, [_, X|_]). + +%% Exercise 4.4 Write a predicate swap12(List1,List2) which checks whether +%% List1 is identical to List2 , except that the first two elements are +%% exchanged. + +swap12([X,Y|T], [Y,X|T]). + +%% Exercise 4.5 Suppose we are given a knowledge base with the following +%% facts: + +tran(eins,one). +tran(zwei,two). +tran(drei,three). +tran(vier,four). +tran(fuenf,five). +tran(sechs,six). +tran(sieben,seven). +tran(acht,eight). +tran(neun,nine). + +%% Write a predicate listtran(G,E) which translates a list of German number +%% words to the corresponding list of English number words. For example: +%% listtran([eins,neun,zwei],X). +%% should give: +%% X = [one,nine,two]. +%% Your program should also work in the other direction. For example, if you give it the query +%% listtran(X,[one,seven,six,two]). +%% it should return: +%% X = [eins,sieben,sechs,zwei]. +%% (Hint: to answer this question, first ask yourself “How do I translate the +%% empty list of number words?”. That’s the base case. For non-empty lists, first +%% translate the head of the list, then use recursion to translate the tail.) +listtran([], []). +listtran([X|TX], [Y|TY]) :- + tran(X, Y), + listtran(TX, TY). + +%% Exercise 4.6 Write a predicate twice(In,Out) whose left argument is a list, +%% and whose right argument is a list consisting of every element in the left +%% list written twice. For example, the query +%% twice([a,4,buggle],X). +%% should return +%% X = [a,a,4,4,buggle,buggle]). +%% And the query +%% twice([1,2,1,1],X). +%% should return +%% X = [1,1,2,2,1,1,1,1]. +%% (Hint: to answer this question, first ask yourself “What should happen when +%% the first argument is the empty list?”. That’s the base case. For non-empty +%% lists, think about what you should do with the head, and use recursion to +%% handle the tail.) +twice([], []). +twice([X|T1], [X,X|T2]) :- + twice(T1, T2). \ No newline at end of file diff --git a/lpn/ch04/list.pl b/lpn/ch04/list.pl new file mode 100644 index 0000000..e979875 --- /dev/null +++ b/lpn/ch04/list.pl @@ -0,0 +1,13 @@ +member(X, [X|_]). +member(X, [_|T]) :- member(X, T). + +memberr(X, X). +memberr(X, [X|_]). +memberr(X, [[H|T1]|T2]) :- + memberr(X, H); + memberr(X, T1); + memberr(X, T2). +memberr(X, [_|T]) :- member(X, T). + +sameLen([], []). +sameLen([_|TA], [_|TB]) :- sameLen(TA, TB). diff --git a/lpn/ch04/notes.md b/lpn/ch04/notes.md new file mode 100644 index 0000000..d554e38 --- /dev/null +++ b/lpn/ch04/notes.md @@ -0,0 +1,30 @@ +## Chapter 4: Lists + +Lists are enclosed in square brackets, and are finite sequences of elements. +Elements can be anything: `[mia, robber(yolanda), X, 2, mia]` or `[mia, +[vincent, jules], [butch, girlfriend(butch)]]` --- a list can contain other +lists. + +Prolog lists use the standard head/tail vocabulary, and the decomposition operator is `|`: + +``` +[Head|Tail] = [mia, [vincent, jules], [butch, girlfriend(butch)]] +``` + +Note that the empty list behaves as one would think. + +``` + ?- [X|Y] = []. + + no +```` + +Arguments can be chained, such as `[X, Y | Z]`. + +### The `member` function + +``` +member(X, [X|_]). +member(X, [_|T]) :- member(X, T). +``` + diff --git a/lpn/ch04/practical.pl b/lpn/ch04/practical.pl new file mode 100644 index 0000000..7aab711 --- /dev/null +++ b/lpn/ch04/practical.pl @@ -0,0 +1,39 @@ +%% 1. Write a 3-place predicate combine1 which takes three lists as arguments +%% and combines the elements of the first two lists into the third as follows: +%% +%% ?- combine1([a,b,c],[1,2,3],X). +%% +%% X = [a,1,b,2,c,3] +%% +%% ?- combine1([f,b,yip,yup],[glu,gla,gli,glo],Result). +%% +%% Result = [f,glu,b,gla,yip,gli,yup,glo] +combine1([], [], []). +combine1([X|TX], [Y|TY], [X,Y|TXY]) :- combine1(TX, TY, TXY). + +%% Now write a 3-place predicate combine2 which takes three lists as arguments +%% and combines the elements of the first two lists into the third as follows: +%% +%% ?- combine2([a,b,c],[1,2,3],X). +%% +%% X = [[a,1],[b,2],[c,3]] +%% +%% ?- combine2([f,b,yip,yup],[glu,gla,gli,glo],Result). +%% +%% Result = [[f,glu],[b,gla],[yip,gli],[yup,glo]] +combine2([], [], []). +combine2([X|TX], [Y|TY], [[X, Y]|TXY]) :- combine2(TX, TY, TXY). + +%% Finally, write a 3-place predicate combine3 which takes three lists as +%% arguments and combines the elements of the first two lists into the third +%% as follows: +%% +%% ?- combine3([a,b,c],[1,2,3],X). +%% +%% X = [j(a,1),j(b,2),j(c,3)] +%% +%% ?- combine3([f,b,yip,yup],[glu,gla,gli,glo],R). +%% +%% R = [j(f,glu),j(b,gla),j(yip,gli),j(yup,glo)] +combine3([], [], []). +combine3([X|TX], [Y|TY], [j(X,Y)|TXY]) :- combine3(TX, TY, TXY). \ No newline at end of file diff --git a/lpn/ch05/arith.pl b/lpn/ch05/arith.pl new file mode 100644 index 0000000..20a9aa9 --- /dev/null +++ b/lpn/ch05/arith.pl @@ -0,0 +1,21 @@ +len([], 0). +len([_|T], N) :- + len(T, X), + N is X+1. + +alen_([], A, A). +alen_([_|H], A, L) :- + A2 is A+1, + alen_(H, A2, L). +alen(X, L) :- alen_(X, 0, L). + +max([], N, N). +max([H|T], N, M) :- + H > N, + max(T, H, M). +max([H|T], N, M) :- + H =< N, + max(T, N, M). + +max([H|T], N) :- + max(T, H, N). \ No newline at end of file diff --git a/lpn/ch05/exercises.pl b/lpn/ch05/exercises.pl new file mode 100644 index 0000000..96840d7 --- /dev/null +++ b/lpn/ch05/exercises.pl @@ -0,0 +1,24 @@ +%% Exercise 5.2 +%% +%% 1. Define a 2-place predicate increment that holds only when its second +%% argument is an integer one larger than its first argument. For example, +%% increment(4,5) should hold, but increment(4,6) should not. +increment(A, B) :- B is A+1. + +%% 2. Define a 3-place predicate sum that holds only when its third argument is +%% the sum of the first two arguments. For example, sum(4,5,9) should hold, but +%% sum(4,6,12) should not. +sum(X, Y, Z) :- Z is X+Y. + +%% Exercise 5.3 +%% +%% Write a predicate addone/2 whose first argument is a list of integers, and +%% whose second argument is the list of integers obtained by adding 1 to each +%% integer in the first list. For example, the query +%% ?- addone([1,2,7,2],X). +%% should give +%% X = [2,3,8,3]. +addone([], []). +addone([X|TX], [Y|TY]) :- + Y is X+1, + addone(TX, TY). \ No newline at end of file diff --git a/lpn/ch05/notes.md b/lpn/ch05/notes.md new file mode 100644 index 0000000..ea5dbbd --- /dev/null +++ b/lpn/ch05/notes.md @@ -0,0 +1,74 @@ +## Chapter 5: Arithmetic in Prolog + +Prolog provides basic arithmetic operators. + +Ex. + +``` + ?- 8 is 6+2. + yes + + ?- 12 is 6*2. + yes + + ?- -2 is 6-8. + yes + + ?- 3 is 6/2. + yes + + ?- 1 is mod(7,2). + yes + + ?- X is 12/4. + X = 3. +``` + +The operators don't actually do arithmetic: + +``` +?- X = 2 + 3. +X = 2+3. +``` + +The default is just to do unification; `is` must be used. The arithmetic +expression must be on the RHS. This part of Prolog is a black box that +handles this, and isn't part of the normal KB and unification parts. + +### Arithmetic and lists + +A recursive list length calculator: + +``` +len([], 0). +len([_|T], N) :- + len(T, X), + N is X+1. +``` + +A tail-recursive length calculator: + +``` +alen_([], A, A). +alen_([_|H], A, L) :- + A2 is A+1, + alen_(H, A2, L). +alen(X, L) :- alen_(X, 0, L). +``` + +Standard notes about tail recursion efficiency apply here. + +### Comparing integers + +* *x < y* → `X < Y.` +* *x ≤ y* → `X =< Y.` +* *x = y* → `X =:= Y.` +* *x ≠ y* → `X =\= Y.` +* *x ≥ y* → `X >= Y` +* *x > y* → `X > Y` + +Note the difference between `=` and `=:=`. + +Let's write a `max` function: + +``` \ No newline at end of file diff --git a/lpn/ch05/practical.pl b/lpn/ch05/practical.pl new file mode 100644 index 0000000..b9b42f3 --- /dev/null +++ b/lpn/ch05/practical.pl @@ -0,0 +1,54 @@ +%% Chapter 5 practical session +%% +%% The purpose of Practical Session 5 is to help you get familiar with Prolog’s +%% arithmetic capabilities, and to give you some further practice in list +%% manipulation. To this end, we suggest the following programming exercises: +%% + +%% 1. In the text we discussed the 3-place predicate accMax which returned the +%% maximum of a list of integers. By changing the code slightly, turn this into +%% a 3-place predicate accMin which returns the minimum of a list of integers. +min([], N, N). +min([H|T], N, M) :- + H < N, + min(T, H, M). +min([H|T], N, M) :- + H >= N, + min(T, N, M). + +min([H|T], N) :- + min(T, H, N). + +%% 2. In mathematics, an n-dimensional vector is a list of numbers of length n. +%% For example, [2,5,12] is a 3-dimensional vector, and [45,27,3,-4,6] is a +%% 5-dimensional vector. One of the basic operations on vectors is scalar +%% multiplication . In this operation, every element of a vector is multiplied +%% by some number. For example, if we scalar multiply the 3-dimensional vector +%% [2,7,4] by 3 the result is the 3-dimensional vector [6,21,12] . +%% +%% Write a 3-place predicate scalarMult whose first argument is an integer, +%% whose second argument is a list of integers, and whose third argument is the +%% result of scalar multiplying the second argument by the first. For example, +%% the query +%% ?- scalarMult(3,[2,7,4],Result). +%% should yield +%% Result = [6,21,12] +scalarMult(_, [], []). +scalarMult(K, [H|T], R) :- + V is K * H, + scalarMult(K, T, [R|V]). + + +%% 3. Another fundamental operation on vectors is the dot product. This +%% operation combines two vectors of the same dimension and yields a +%% number as a result. The operation is carried out as follows: the +%% corresponding elements of the two vectors are multiplied, and the +%% results added. For example, the dot product of [2,5,6] and [3,4,1] is +%% 6+20+6 , that is, 32 . Write a 3-place predicate dot whose first +%% argument is a list of integers, whose second argument is a list of +%% integers of the same length as the first, and whose third argument is +%% the dot product of the first argument with the second. For example, +%% the query +%% ?- dot([2,5,6],[3,4,1],Result). +%% should yield +%% Result = 32 \ No newline at end of file