I am using DrRacket to learn Scheme, The language subset is racket (#lang racket). I have the following list/expression:
(cons (cons (cons 'a 'b) (cons 'c 'd)) (cons (cons 'e 'f) (cons 'g 'h)))
When I press enter I get the following value printed out:
'(((a . b) c . d) (e . f) g . h)
I would expect the result to be:
'((( a . b) (c . d)) ((e . f) ( g . h)))
Can anyone explain what rules scheme uses to decide to print the value the way it does?
Attached is also a screen of the terminal:
cons creates a pair, which is also a list. So, when you later cons something else to a list, you extend this list.
(cons 'a 'b)
==> (a . b)
(cons 'c '(a . b))
==> (c a . b)
(cons 'd '(c a . b))
==> (d c a . b)
And this is what happens when you cons new pair to another pair/list:
(cons 'something '(c . d))
==> (something c . d)
(cons '(a . b) (c . d))
==> ((a . b) c . d)
Sometimes it's helpful to draw pairs as boxes to see what is going on:
(cons 'a 'b) (cons 'c 'd)
+---+---+ +---+---+
| | |--- b | | |--- d
+---+---+ +---+---+
| |
a c
(cons (cons 'a 'b) (cons 'c 'd))
+---+---+ +---+---+
| | |--- | | |--- d
+---+---+ +---+---+
| |
| c
+---+---+
| | |--- b
+---+---+
|
a
To get ((a . b) (c . d)) you have to:
(cons (cons 'a 'b) (cons (cons 'c 'd) '()))
==> ((a . b) (c . d))
+---+---+ +---+---+
| | |------- | | |--- NIL/()
+---+---+ +---+---+
| |
| |
+---+---+ +---+---+
| | |--- b | | |--- d
+---+---+ +---+---+
| |
a c
The result of your expression is:
'((( a . b) . (c . d)) . ((e . f) . ( g . h)))
and not
'((( a . b) (c . d)) ((e . f) ( g . h)))
as you are expecting.
However it is not printed in that way, for the rules of printing of lisp languages. See for instance this page (it is for Common Lisp, but the printing rules are the same for Scheme):
Notice that LISP prints linked lists a special way: it omits some of
the periods and parentheses. The rule is: if the cdr of a cons is nil,
LISP doesn't bother to print the period or the nil; and if the cdr of
cons A is cons B, then LISP doesn't bother to print the period for cons
A or the parentheses for cons B. So:
(cons 4 nil)
(4)
(cons 4 (cons 5 6))
(4 5 . 6)
(cons 4 (cons 5 (cons 6 nil)))
(4 5 6)
Related
How would I write a function in Dr. Racket which consumes a list of 2 possible symbols ('c or 'v) and replaces them with something else?
If the symbol is 'c, then it gets replaced with 'c 'v
If the symbol is 'v, then it gets replaced with 'v 'c
Here is my code so far:
(define (awesome c)
(cond
[(equal? c 'c) (list 'c 'v)]
[else (list 'v 'c)]))
(define (substitute los)
(map awesome los))
If I type in:
(substitute (list 'c 'v 'c 'c))
My desired output is
(list 'c 'v 'v 'c 'c 'v 'c 'v)
Instead, I get:
(list (list 'c 'v) (list 'v 'c) (list 'c 'v) (list 'c 'v))
Why is this happening? How can I correct my code to achieve the correct output? Thanks.
A Simple Solution
Each symbol in the input is generating a list of two symbols in the output. Use append to combine the lists, e.g.:
scratch.rkt> (append '(c v) '(v c) '(c v) '(c v))
'(c v v c c v c v)
Since map is creating a list that contains sublists, use apply to apply append to the sublists:
(define (substitute los)
(apply append (map awesome los)))
Sample interaction:
scratch.rkt> (substitute (list 'c 'v 'c 'c))
'(c v v c c v c v)
Adding Some Flexibility
You could take a more flexible approach by using a list of term rewriting rules. This would allow you to change the substitution rules without changing your code. The term rewriting rules could be represented as a list of lists, with an arrow separating the input term from the rewrites:
(define cv-rules '((c -> c v)
(v -> v c)))
It is useful to define a couple of functions that get the rule for a term and a list of rewrites from a rule. Abstracting these operations to functions makes it easier to change the representation of a rule later, and helps keep the code clear:
(define (get-rule term rules)
(assoc term rules))
(define (get-rewrites rule)
(cddr rule))
This get-rewrites function can be used in another function that rewrites a term based on the rules. Here, any symbol which does not have a specific rule is just returned in a list by itself:
(define (rewrite-term x rules)
(let ((rule (get-rule x rules)))
(if rule
(get-rewrites rule)
(list x))))
Now the rewrite-term function can be mapped over the input, together with rewrite rules. As before, the mapping results in a list of sublists, so append is applied to the result before returning:
(define (rewrite terms rules)
(apply append (map (lambda (x) (rewrite-term x rules)) terms)))
Now you can easily change the way that substitutions are made by defining a new set of rewrite rules.
Sample interactions:
scratch.rkt> (rewrite '(c v c c) cv-rules)
'(c v v c c v c v)
scratch.rkt> (rewrite '(c v c x c) cv-rules)
'(c v v c c v x c v)
Recursively Rewriting
With a small change to the rewrite-term function, you can apply the rewrite rules recursively to nested lists of terms. When the term to rewrite is itself a nonempty list with no rewrite rule, rewrite is called on that term. Note that all rewrites are wrapped in lists before being returned. This new function behaves as before for the original rules, but allows more complex rules, too:
(define (rewrite-term x rules)
(let ((rule (get-rule x rules)))
(cond (rule (get-rewrites rule))
((pair? x) (list (rewrite x rules)))
(else
(list x)))))
Sample interactions:
scratch.rkt> (define cv2-rules '((c -> v)
(v -> (c v))))
scratch.rkt> (rewrite '(c v c c) cv2-rules)
'(v (c v) v v)
scratch.rkt> (rewrite '(v (c v) v v) cv2-rules)
'((c v) (v (c v)) (c v) (c v))
scratch.rkt> (rewrite '((c v) (v (c v)) (c v) (c v)) cv2-rules)
'((v (c v)) ((c v) (v (c v))) (v (c v)) (v (c v)))
You approach was quite good.
All you have to do is to replace map by append-map.
(define (awesome c)
(cond ((equal? c 'c) (list 'c 'v))
((equal? c 'v) (list 'v 'c))))
(define (substitute los)
(append-map awesome los))
(substitute (list 'c 'v 'c 'c))
;; '(c v v c c v c v)
;; desired: (list 'c 'v 'v 'c 'c' 'v 'c 'v)
After solving my error with values-list and being able to run my program until the end, I found that my diagonal check seems to have a logic error. My input is as follows:
(THREAT? '(1 3) '((1 0)(2 4)(3 0)(4 0)(5 0)(6 0)(7 0)(8 0)))
The first argument being a board space that we are testing is ok or not to place a queen and the second argument is the state of the board, y values 1-8 determine the column positions of a piece and a 0 value would indicate that x value row would hold no piece. My code is as follows:
(defun diagonal(point1 point2)
(= (abs (- ( car point1 ) ( car point2 )))
(abs (- ( cadr point1 ) ( cadr point2 ))))
)
(defun THREAT?(x y)
; Checks threat on the vertical
(when (not (eq (values-list (cdr (nth (- (car x) 1 ) y )) ) '0 ) )
(return-from THREAT? t)
)
(loop for i from 0 to (list-length y)
; Checks threat on the horizontal
when (eq (values-list ( cdr x )) (values-list (cdr (nth i y))) )
do (return-from THREAT? t)
; With the help of the diagonal function checks along the diagonal
when (diagonal x (nth i y) )
do (return-from THREAT? t)
)
)
If my understanding is correct my program should loop through every single element of y. It will pass the x and the current y pair to the diagonal function. The diagonal function will minus the two and absolute value them and check if they are equal (if they are diagonal then they should be ex. (1 2) and (2 3) are diagonal and therefore |1 - 2| = 1 and |2 - 3| = 1). The diagonal function should return true if these numbers are equivalent. The corresponding when statement should only activate when it receives a true from the diagonal function and yet it seems to always return true, even when I give the program a completely blank board. How do I fix diagonal to correctly determine a threat on the board? Any and all help is greatly appreciated!
I have rewritten your code to better Lisp style.
much better naming.
procedures with useful names make comments redundant
individual procedures are better testable
got rid of the VALUES-LIST nonsense
get rid of all CAR, CDR, CADR. Use FIRST and SECOND.
introduced accessors for x and y components of a point
got rid of the strange control flow with RETURN-FROM, replaced it with a simple OR
actually directly iterate over a list, instead of using NTH all the time
EQ is not for comparing number equality, use = instead
don't place parentheses alone on a line.
indent and format the code correctly
don't put spaces between parentheses
put a space between an atom and an open parenthesis
Code:
(defun get-x (point)
(first point))
(defun get-y (point)
(second point))
(defun diagonal? (point1 point2)
(= (abs (- (get-x point1) (get-x point2)))
(abs (- (get-y point1) (get-y point2)))))
(defun vertical? (point)
(not (zerop (get-y point))))
(defun horizontal? (point1 point2)
(= (get-y point1)
(get-y point2)))
(defun threat? (point list-of-columns)
(or (vertical? (nth (1- (get-x point)) list-of-columns))
(loop for point2 in list-of-columns
when (or (horizontal? point point2)
(diagonal? point point2))
return t)))
Example
Now we can trace the three threat predicates:
? (trace vertical? diagonal? horizontal?)
NIL
Now you can call your example:
? (threat? '(1 3) '((1 0) (2 4) (3 0) (4 0) (5 0) (6 0) (7 0) (8 0)))
0> Calling (VERTICAL? (1 0))
<0 VERTICAL? returned NIL
0> Calling (HORIZONTAL? (1 3) (1 0))
<0 HORIZONTAL? returned NIL
0> Calling (DIAGONAL? (1 3) (1 0))
<0 DIAGONAL? returned NIL
0> Calling (HORIZONTAL? (1 3) (2 4))
<0 HORIZONTAL? returned NIL
0> Calling (DIAGONAL? (1 3) (2 4))
<0 DIAGONAL? returned T
T
This should help, so that you can better debug your code... Look at the trace output.
A version which does not use empty column descriptions
(defun get-x (point)
(first point))
(defun get-y (point)
(second point))
(defun diagonal? (point1 point2)
(= (abs (- (get-x point1) (get-x point2)))
(abs (- (get-y point1) (get-y point2)))))
(defun vertical? (point list-of-columns)
(let ((point2 (find (get-x point) list-of-columns :key #'get-x)))
(and point2 (not (zerop (get-y point2))))))
(defun horizontal? (point1 point2)
(= (get-y point1)
(get-y point2)))
(defun threat? (point list-of-columns)
(or (vertical? point list-of-columns)
(loop for point2 in list-of-columns
when (or (horizontal? point point2)
(diagonal? point point2))
return t)))
(defun print-board (board)
(format t "~%+-+-+-+-+-+-+-+-+")
(dotimes (y 8)
(terpri)
(dotimes (x 8)
(format t "|~a" (if (member (list x y) board :test #'equal) "x" " ")))
(format t "|~%+-+-+-+-+-+-+-+-+")))
Example:
CL-USER 138 > (threat? '(1 2) '((2 4)))
NIL
CL-USER 139 > (print-board '((1 2) (2 4)))
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
| |x| | | | | | |
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
| | |x| | | | | |
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
NIL
Another example:
CL-USER 140 > (threat? '(1 2) '((2 4) (4 5)))
T
CL-USER 141 > (print-board '((1 2) (2 4) (4 5)))
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
| |x| | | | | | |
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
| | |x| | | | | |
+-+-+-+-+-+-+-+-+
| | | | |x| | | |
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
| | | | | | | | |
+-+-+-+-+-+-+-+-+
NIL
Suppose we define a relation matches via the following table:
|-----+-----+-----+-----+-----|
| | *A* | *B* | *C* | *D* |
|-----+-----+-----+-----+-----|
| *A* | | X | X | |
|-----+-----+-----+-----+-----|
| *B* | X | | | X |
|-----+-----+-----+-----+-----|
| *C* | X | | | |
|-----+-----+-----+-----+-----|
| *D* | | X | | |
|-----+-----+-----+-----+-----|
By this, it is meant that (in pseduo-code)
(matches A) ;=> (B C)
(matches B) ;=> (A D)
(matches C) ;=> (C)
(matches D) ;=> (B)
In core.logic, I think I would know how to make individualized functions which could approximate the behavior of matches:
(defn matches-A
(run* [q]
(membero q [B C]))) ;=> (B C)
...and so forth for matches-B and matches-C.
Question: How could I generalize, i.e., matches-A to a single function matches as above? In particular, I'd be interested in making it so that you could run queries like (matches "not A"), (matches "B and C") and (matches "C or D") (in pseudo-code) to get results like (A D), (A), and (A B) respectively. Is this possible?
NOTE: I'm using clojurescript instead of clojure. I'm not sure if that would impact the answer at all.
You can use conde to solve this task:
(ns qradv.welcome
(:require [cljs.core.logic :as l]))
;; |-----+-----+-----+-----+-----|
;; | | *A* | *B* | *C* | *D* |
;; |-----+-----+-----+-----+-----|
;; | *A* | | X | X | |
;; |-----+-----+-----+-----+-----|
;; | *B* | X | | | X |
;; |-----+-----+-----+-----+-----|
;; | *C* | X | | | |
;; |-----+-----+-----+-----+-----|
;; | *D* | | X | | |
;; |-----+-----+-----+-----+-----|
(defn matches [x]
(l/run* [y]
(l/conde
[(l/== x "A") (l/membero y ["B" "C"])]
[(l/== x "B") (l/membero y ["A" "D"])]
[(l/== x "C") (l/membero y ["C"])]
[(l/== x "D") (l/membero y ["B"])])))
(prn (matches "A"))
(prn (matches "B"))
(prn (matches "C"))
(prn (matches "D"))
Output:
("B" "C")
("A" "D")
("C")
("B")
Is there a built-in procedure to check if a list is cyclic in Scheme (R5RS)? And when is a list cyclic (per definition)? I have tried to find some procedure that checks this, and how it is implemented, but I haven't been able to find one.
A list is circular per definition if the cdr of the tail (last element) points to the head of the list. However, you can also have a circular list where the cdr of the tail points to an arbitrary element in the list. A good algorithm to detect a circular list is the tortoise and hare algorithm. An example implementation is given at this page.
The code is as follows (credit to the author of the page linked above):
Edit: I modified the code because it contained an error pointed out by Sylwester.
(define (has-cycle-h slow-ls fast-ls)
(cond
((null? fast-ls) #f)
((null? (cdr fast-ls)) #f)
((eq? slow-ls fast-ls) #t)
(else (has-cycle-h (cdr slow-ls) (cddr fast-ls)))))
(define (has-cycle? ls)
(cond
((null? ls) #f)
(else (has-cycle-h ls (cdr ls)))))
;; Create cyclic list
(define l (cons 1 (cons 2 (cons 3 (cons 4 '())))))
(set-cdr! (cdr (cdr (cdr l))) l)
;; Results in:
;+---+ +---+ +---+ +---+
;| 1 +--->| 2 +-->| 3 +--->| 4 |
;+-+-+ +---+ +---+ +-+-+
; ^ |
; | |
; +-------------------------+
(has-cycle? l) ; Evaluates to #t
;; Create list
(define l (cons 1 (cons 2 (cons 3 (cons 4 '())))))
;; Make it circular by pointing the tail to the second element.
(set-cdr! (cdr (cdr (cdr l))) (cdr l))
;; Results in:
;+---+ +---+ +---+ +---+
;| 1 +--->| 2 +-->| 3 +--->| 4 |
;+---+ +-+-+ +---+ +-+-+
; ^ |
; | |
; +----------------+
(has-cycle? l) ; Evaluatores to #t
; Regular list
(has-cycle? '(1 1 1 1 1 1 1)) ; Evaluates to #f
There is no BIF for detecting a circular list.
There is circular-list? predicate in SRFI 1. The definition of circular list in SRFI 1 is: "A circular list is a value such that for every n>=0, cdr^n(x) is a pair." It means that there is no end of the list. The first pair of the circular list does not need to be part of a cycle. It is enough that one eventually by following the cdrs reaches a cycle.
SRFI 1 has this description on non-circular lists:
(not (circular-list? x)) = (or (proper-list? x) (dotted-list? x))
SRFI 1 is not in R5RS per se, but all implementations I know of come with srfi 1 included. Note that if srfi1 is implemented in the runtime, the circular-list? predicate from srfi 1 could be faster than a Scheme implementation of the tortoise-and-hare algorithm. Benchmark your implementation of choice to find out how your implementation behaves.
http://srfi.schemers.org/srfi-1/srfi-1.html#circular-list-p
I'm trying to understand the relations between pair, cons, dotted tuples and proper list in PLT-Scheme 372. The detailed context of my question is as follows:
After reading some textbook and doing trial-and-error, I have got the following understanding and intuitive ideas (I may be wrong...):
all lists are pairs, e.g.:
(pair? (list 'a 'b 'c)) => #t
all conses are pairs, e.g.:
(pair? (cons 'a (cons 'b 'c))) => #t
some dot-separated tuples are pairs, e.g.:
(pair? '(a . b)) => #t
(pair? '(a . b . c)) => #t in Standard R5RS it's not legal syntax.
Then I bumped into this problem: Why does '(a . b . c) evaluate to (b a c)? Where can I find a complete usage manual of dot?
'(a . b) => (a . b)
'(a . b . c) => (b a c)
'(a . b . c . d) => illegal use of `.'
'(cons 'a (cons 'b 'c)) => (a b . c)
For Racket (PLT), there is a good description here.
Regarding the syntax (a . b . c) look at the bottom of the page, it's a Racket-specific reader extension designed to express typical tests like (< 1 2) as (1 . < . 2).