How does append-to-form work? (SICP's section on Logic Programming) - sicp

I am currently working through SICP's section on Logic Programming, but I got stuck in the examples regarding logical deductions, especially the append-to-form rules. How do they work? What I don't quite understand is how the second rule cdr-downs the first list. For example, given:
(rule (append-to-form () ?y ?y))
(rule (append-to-form (?u . ?v) ?y (?u . ?z))
(append-to-form ?v ?y ?z))
a) How do we reach from:
;;; Query input:
(append-to-form (a b) (c d) ?z)
to
;;; Query results:
(append-to-form (a b) (c d) (a b c d))
b) And what bout this one:
;;; Query input:
(append-to-form (a b) ?y (a b c d))
to
;;; Query results:
(append-to-form (a b) (c d) (a b c d))
c) And lastly:
;;; Query input:
(append-to-form ?x ?y (a b c d))
to
;;; Query results:
(append-to-form () (a b c d) (a b c d))
(append-to-form (a) (b c d) (a b c d))
(append-to-form (a b) (c d) (a b c d))
(append-to-form (a b c) (d) (a b c d))
(append-to-form (a b c d) () (a b c d))
I would be interested in the specific mental steps required to carry out the rule matching.
Thank you in advance.

Play interpreter by taking a piece of paper and writing down every single step. For every step you write down which rule was/can be triggered and what variable was bound to what value.
For example:
(append-to-form (a b) (c d) ?z)
triggers the rule
(rule (append-to-form (?u . ?v) ?y (?u . ?z))
(append-to-form ?v ?y ?z))
with
?u = a, ?v = (b), ?y = (c d), ?z = (a . ?z_2)
Note: ?z in the original query is supposed to be a different variable from ?z in the rule body, therefor rename the rule's ?z into ?z_2. A list (1 2 3) when matched to (?a . ?b) produces ?a = 1, ?b = (2 3) like when car/cdr'ing a list.
These bindings are applied to the body of the rule (append-to-form ?v ?y ?z) So we get
(append-to-form (b) (c d) ?z_2)
which again becomes
(append-to-form () (c d) ?z_3)
and triggers a different rule: (rule (append-to-form () ?y ?y)) binding ?z_3 to (c d).
Then recursion kicks in, ?z_2 was defined as (b . ?z_3), ?z was defined as (a . ?z2)
The original query (append-to-form (a b) (c d) ?z) gets applied to the bindings in which ?z = (a . (b . (c d))) and returns (append-to-form (a b) (c d) (a b c d))
The rest of the exercises are left to the reader ;)
The crucial concepts here are pattern matching and unification which can be found at section 4.2.2. The whole query evaluator is really the most difficult piece in SICP, so don't be discourage. It is well worth the effort. Try to run the code (in an R5RS Scheme) and fiddle with it, such as adding tracing.

Related

Need hints about proving some intuitionistic logic statements

I'm new to Agda, and I'm new to dependently typed programming and proof assistants in general. I decided to get myself started by constructing simple intuitionistic logic proofs, using the definitions I found in Programming Language Foundations in Agda, and I had some success. However, I got confused when I tried to write the following proof:
∨-identity-indirect : {A B : Set} → (¬ A) ∧ (A ∨ B) → B
Proving this on paper would be fairly simple: expanding ¬ A, we have A → ⊥. So this statement becomes equivalent to (⊥ ∨ B) → B, which is obviously true.
I was able to successfully prove the latter part, that is, (⊥ ∨ B) → B:
∨-identity : {A : Set} → (⊥ ∨ A) → A
∨-identity (∨-left ())
∨-identity (∨-right A) = A
Then, I was able to write:
∨-identity-indirect ⟨ ¬A , A∨B ⟩ = ∨-identity ?
Suggesting me that I need to produce ⊥ ∨ B by having ¬A and A ∨ B. I'd like to somehow replace A in A ∨ B with ¬A A, but I don't think there's a way of doing so.
When trying to apply the ∨-identity case analysis pattern to ∨-identity-indirect, I get an error message that A should be empty, but that's not obvious to me - I assume I need to somehow make this obvious to Agda, by making use of ¬A.
Am I on the right track, or am I getting this wrong completely? How should I go about writing this ∨-identity-indirect function?
Suggesting me that I need to produce ⊥ ∨ B by having ¬A and A ∨ B. I'd like to somehow replace A in A ∨ B with ¬A A, but I don't think there's a way of doing so.
When trying to apply the ∨-identity case analysis pattern to ∨-identity-indirect, I get an error message that A should be empty, but that's not obvious to me - I assume I need to somehow make this obvious to Agda, by making use of ¬A.
You're probably trying to pattern match on a value of type ¬ A with (), which doesn't work, because ¬ A expands to A -> ⊥, i.e. it's a function that will only return you a ⊥ after you give it some A. Here is how you do that:
replace-A : {A B : Set} → (¬ A) → (A ∨ B) → ⊥ ∨ B
replace-A f (v-left x) = v-left (f x)
replace-A _ (v-right y) = v-right y
Having that, ∨-identity-indirect is straightforward:
∨-identity-indirect : {A B : Set} → (¬ A) ∧ (A ∨ B) → B
∨-identity-indirect ⟨ ¬A , A∨B ⟩ = ∨-identity (replace-A ¬A A∨B)

How to go count all of the atoms in a list (or a list of nested lists) when you use recursion

I am creating a recursive function that counts the number of atoms inside a list. It should be able to count the atoms of lists that are nested.
For example: (a (b c) e d) or (a (b c (g e)) e d), it should count b and c separately or b, c, e, and d separately and not as a whole.
This is the function that I have created:
(defun count-atoms (mylist)
(cond
((null mylist) 0)
((listp (car mylist)) (count-atoms (car mylist)))
((atom (car mylist)) (+ 1 (count-atoms (rest mylist))))
)
)
The output I get is 3 but it should be 5 (based from (a (b c) e d)). I am guessing that the function stops the moment it reaches c. How do i make the function not stop at c and make it go back to the outermost list.
Here's a way we can reason about the problem -
If the input is null, return zero
'( )
^
| 0 atoms
(inductive) Otherwise the input has at least one element. If car is a list, call count-elements on car and cdr. Add the two results together and return.
'( a b c d ... )
^ ^
| | count atoms in cdr <-
| \
| count atoms in sublist <------\_ add together
(inductive) Otherwise the input has at least one element that is not a list. Call count-elements on cdr. Add one to the result and return.
'( a b c d ... )
^ ^
| | count atoms in cdr <-
| \
| one atom <-----------------\_ add together
Do you see where your program differs?
Your mistake is that you are ignoring the tail in the second clause.
(defun count-atoms (tree)
"Count atoms in all leaves of the tree, ignoring terminating NIL."
(if tree
(+ (if (atom (car tree))
1
(count-atoms (car tree)))
(count-atoms (cdr tree)))
0))
now
(count-atoms '(a (b c) e d))
==> 5
(count-atoms '(a (b c (g e)) e d))
==> 7
(count-atoms '(a (b c (g e)) nil e d))
==> 8

Given A∧B what is the equivalent using just → and ⊕(Xor)

Consider the set of connectives consisting of just → and ⊕, where ⊕ is an exclusive OR connective: A⊕B is true if and only if A and B have the opposite truth values (one is true and the other one false).
Given A∧B what is the equivalent formula using only → and ⊕(Xor).
Assumming that -> is the material conditional.
A and B is equivalent to not(A implies not B)
not C is equivalent to (C implies C) xor C
so
not B is equivalent to (B implies B) xor B)
and
A implies not B equivalent to A implies ((B implies B) xor B))
finally the equivalent expression is
((A implies ((B implies B) xor B)) implies (A implies ((B implies B) xor B)))xor (A implies ((B implies B) xor B))
in your notation:
((A → ((B → B) ⊕ B)) → (A → ((B → B) ⊕ B)))⊕ (A → ((B → B) ⊕ B))
with some care you can surely minimize these formulas
Checking the final formula on wolfram alpha
A general framework to answer such questions is functional completness.
The people at mathoverflow might be helpful.
EDIT
i've made a mess of copying the long formulas, corrected now

Scheme / Racket insert-everywhere function with sublists

So I've been trying to solve this problem:
Given an element E and a list L insert E into every position in the list L (so the result is a list of lists). Example:
(insert-everywhere 'a '(b c)) would give ((a b c) (b a c) (b c a))
This is easy enough but there is one other condition in my problem that is making it difficult for me - if an element of L is a list itself then the element must also be inserted into every position in the sublist. For example:
(insert-everywhere 'd '(a (b c))) would return: ((d a (b c)) (a d (b c)) (a (d b c)) (a (b d c)) (a (b c d)) (a (b c) d)).
This is the code I have so far (which I mostly lifted from here):
#lang racket
(define (insert-at pos elmt lst)
(if (empty? lst) (list elmt)
(if (list? (car lst)) (insert-everywhere elmt (car lst))
(if (= 1 pos)
(cons elmt lst)
(cons (first lst)
(insert-at (- pos 1) elmt (rest lst)))))))
(define (insert-everywhere sym lst)
(remove-duplicates
(map (lambda (i)
(insert-at i sym lst))
(range 1 (+ 2 (length lst))))))
where this line: (if (list? (car lst)) (insert-everywhere elmt (car lst)) is supposed to handle the sublists but it isn't working. (If I run (insert-everywhere 'd '(a (b c))) with the above code I get ((d a (b c)) (a (d b c) (b d c) (b c d))))
If anyone has suggestions on how to approach this differently I'd be happy to hear.
I wouldn't do indexing as it is very inefficient. Rather reverse the input list and build the list from end to beginning making the results in reverse order. You have a current list that you add elements to with cons that you use to add new additions to the results and each level each result that existed gets the one element added too.
As parameters you have state. When i made a reference I used result and cur and typically my iteration did like this for (insert-everywhere 'd '(a b c)):
lst cur results
(c b a) () ((d))
(b a) (c) ((d c) (c d))
(a) (b c) ((d b c) (b d c) (b c d))
() (a b c) ((d a b c) (a d b c) (a b d c) (a b c d)))
Now adding support for sublists are just doing the same with them and then do a map such that you create one result per sublist in the result, adding cur in addition to adding it as an element.
Notice all new results are just cur with an added inserted element and all th erest gets a new element in fron which is the first element of the input. cur will grow and it is shared so only the elements up to the inserted element will be unique to that sub result.
I have a working implementation, but it's no fun getting the solution prematurely. Have fun.

"On Lisp": `(a b c) vs '(a b c) vs (list 'a 'b 'c)

In On Lisp (p. 84) Graham says
‘(a b c) (without comma) is equal to ’(a b c)
and then says
A backquoted list is equivalent to a call to list with the elements
quoted.That is, ‘(a b c) (without comma) is equal to (list ’a ’b ’c).
One statement has to be false since '(a b c) and (list 'a 'b 'c) don't seem to be equal. The latter is a freshly consed list (safe to modify) while the former is a constant -- or at least the spec allows the compiler to treat it as such.
So maybe it's a very nitpicky question but is a backquoted list (without comma) like ‘(a b c) equal to '(a b c) or equal to (list 'a 'b 'c)?
Equal and Equivalent are not the same.
Certainly (equal '(a b c) (list 'a 'b 'c)) returns t, but, as you correctly note yourself, '(a b c) is a quoted constant while (list 'a 'b 'c) is freshly allocated.

Resources