From 2c9702f3341926408500b8c4c0f840926e6cd555 Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Thu, 25 Jan 2018 17:57:27 -0800 Subject: [PATCH] Start chapter 6. --- lpn/ch06/append.pl | 13 ++++++++++++ lpn/ch06/notes.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 lpn/ch06/append.pl create mode 100644 lpn/ch06/notes.md diff --git a/lpn/ch06/append.pl b/lpn/ch06/append.pl new file mode 100644 index 0000000..b880c39 --- /dev/null +++ b/lpn/ch06/append.pl @@ -0,0 +1,13 @@ +append([], L, L). +append([H|T], L2, [H|L3]) :- append(T, L2, L3). + +prefix(P, L) :- append(P, _, L). +suffix(S, L) :- append(_, S, L). + +sublists(SubL, L) :- suffix(S, L), prefix(SubL, S). + +%% reverse([], []). +%% reverse([H|T], R) :- reverse(T, RevT), append(RevT, [H], R). + +reverse([], A, A). +reverse([H|T], A, R) :- reverse(T, [H|A], R). diff --git a/lpn/ch06/notes.md b/lpn/ch06/notes.md new file mode 100644 index 0000000..f827840 --- /dev/null +++ b/lpn/ch06/notes.md @@ -0,0 +1,52 @@ +## Chapter 6: More lists + +### append + +append(L1, L2, L3) ⇒ K3 ← L1 + L2 + +Definition: + +``` +append([], L, L). +append([H|T], L2, [H|L3]) :- append(T, L2, L3). +``` + +> [This] illustrates a more general theme: the use of unification to build +> structure. In a nutshell, the recursive calls to append/3 build up this +> nested pattern of variables which code up the required answer. When Prolog +> finally instantiates the innermost variable `_G593` to `[1, 2, 3]`, the +> answer crystallises out, like a snowflake forming around a grain of dust. +> But it is unification, not magic, that produces the result. + +The most obvious use is concatenation; but we can build other predicates, too: + +``` +prefix(P, L) :- append(P, _, L). +suffix(S, L) :- append(_, S, L). +``` + +We can generate sublists: the text notes that the sublists are the suffixes of +the prefixes of the list. In retrospect, it makes sense. This can be defined as + +``` +sublists(SubL, L) :- suffix(S, L), prefix(SubL, S). +``` + +## Reversing a list + +`append/3` isn't always what we want and is pretty inefficient. For example, if +we want to reverse a list using the following recursive definition: + +1. Reversing the empty list returns the empty list. +2. Otherwise, given [H|T], return [reverse(T)|[H]] + + +``` +reverse([], []). +reverse([H|T], R) :- reverse(T, RevT), append(RevT, [H], R). +``` + +If a trace is run on a call, it's apparent it's doing a lot of extra work. For +example, given `reverse([a, b, c, d, e], R)`, 12 calls are made to `reverse` +and 30 calls to `append`. +