I am a composer usually working with Max-MSP and OpenMusic.
For porting some work from OM to Max, I have just started to learn LISP.
My problem is rather simple: I want to make chord inversions from a given chord.
From (C E G) it needs to return ((C E G) (E G C) (G C E)). It means that for a 3 notes chord I'll get 3 inversions and for n notes chord n inversions.
I've already built the basic functions:
(defun if-x-under-y-raise-x (x y)
(if (<= x y) (if-x-under-y-raise-x (+ x 12) y) x))
(defun transp (chord)
(append (cdr chord)
(cons (if-x-under-y-raise-x (first chord) (list-max chord 0)) nil)))
transp function takes the lowest note of a sorted chord and transpose it by one octave until it is higher than the highest note of the chord recursively.
So expressed in MIDI it means that (60 64 67) becomes (64 67 72). This is very easy to do.
Problems come when I want to get the n inversions recursively as explained before.
I can do it once with transp but the function below doesn't work:
(defun renverse (chords)
(if (< (length (first chords)) (length chords))
chords
(cons chords (renverse (list (transp (last chords)))))))
chords is the starting list.
(renverse '(60 64 67)) should return 3 chord inversions.
Any help will be very welcome.
:-)
LOOP:
(defun renverse (chord)
(loop for chord0 = chord then (transp chord0)
repeat (length chord)
collect chord0))
Recursive (with the usual call stack depth limitation):
(defun renverse (chord &optional (n (length chord)))
(cons chord
(if (= n 1)
nil
(renverse (transp chord) (1- n)))))
Example:
CL-USER 19 > (renverse '(60 64 67))
((60 64 67) (64 67 72) (67 72 76))
You could also write it in some neutral list processing style:
(defun mutate-list-n-times-by-fn (list &key (n (length list)) (fn #'identity))
(loop for l = list then (funcall fn l)
repeat n
collect l))
(defun renverse (chord)
(mutate-list-n-times-by-fn chord :fn #'transp))
Related
(Just for fun) I figured out a way to represent this:
250 : 8 = 31 + 2
31 : 8 = 3 + 7
∴ (372)8
in the following procedure:
(defun dec->opns (n base)
(do* ((lst nil (append lst (list pos))) ; this is also not so nice
(m n (truncate m base))
(pos (rem m base) (rem m base)) ) ; <<<<<<
((< m base) (reverse (append lst (list m)))) ))
The procedure does what it is supposed to do until now.
CL-USER> (dec->opns 2500000 8)
(1 1 4 2 2 6 4 0)
At this point, I simply ask myself, how to avoid the two times
(rem m base).
First of all because of duplicates are looking daft. But also they may be a hint that the solution isn't the elegant way. Which also is not a problem. I am studying for becoming a primary school teacher (from 1st to 6nd class) and am considering examples for exploring math in a sense of Paperts Mindstorms. Therefore exploring all stages of creating and refining a solution are welcome.
But to get a glimpse of the professional solution, would you be so kind to suggest a more elegant way to implement the algorithm in an idiomatic way?
(Just to anticipate opposition to my "plan": I have no intentions to overwhelm the youngsters with Common Lisp. For now, I am using Common Lisp for reflecting about my study content and using the student content for practicing Common Lisp. My intention in the medium term is to write a "common (lisp) Logo setup" and a Logo environment with which the examples in Harveys Computer Science Logo style (vol. 1), Paperts Mindstorms, Solomons et. al LogoWorks, and of course in Abelsons et. al Turtle Geometry can be implemented uncompromisingly. If I will not cave in, the library will be found with quickload in the still more distant future under the name "c-logo-s" and be called cλogos ;-) )
The closest to your code
You can reduce the reversing of the reversing and append -> by using cons only. The duplication of (rem m base) is only an optical issue, since the first (rem m base) gets executed only the first time the loop runs and the second (rem m base) in all other cases. Thus they are actually not a duplication. One cannot use a let here, because of the required syntax within the macro. (<variable> <initial-value> <progression-for-each-round>)
(defun dec->ops (n base)
(do* ((acc nil (cons r acc))
(m n (truncate m base))
(r (rem m base) (rem m base)))
((zerop m) acc)))
The most Common Lispy version
The rosetta solutions for Common Lisp seems to give the most Common Lisp-like ways - either using write-to-string/parse-integer or even some format quircks.
(defun decimal->base-n (n base)
(write-to-string n :base base))
(defun base-n->decimal (base-n base)
(parse-integer (format nil "~a" base-n) :radix base))
(defun decimal-to-base-n (number &key (base 16))
(format nil (format nil "~~~dr" base) number))
(defun base-n-to-decimal (number &key (base 16))
(read-from-string (format nil "#~dr~d" base number)))
;; or:
(defun change-base (number input-base output-base)
(format nil "~vr" output-base (parse-integer number :radix input-base)))
Source: https://rosettacode.org/wiki/Non-decimal_radices/Convert#Common_Lisp
(decimal-to-base-n 2500000 :base 8)
;;=> "11422640"
Solution without format or write-to-string/parse-integer
Use tail call recursion:
(defun dec->ops (n base &optional (acc nil))
(if (< n base)
(cons n acc)
(multiple-value-bind (m r) (truncate n base)
(dec->ops m base (cons r acc)))))
Try it:
[41]> (dec->ops 250 8)
(3 7 2)
[42]> (dec->ops 250000 8)
(7 5 0 2 2 0)
[43]> (dec->ops 2500000 8)
(1 1 4 2 2 6 4 0)
The do/do* macros are in this case not so nice, because one cannot capture the multiple values returned by truncate nicely (truncate is mod and rem in one function - one should use this fact).
If you really wants to use do*
(defun dec->ops (n base)
(do* ((acc nil (cons (second values) acc))
(values (list n) (multiple-value-list (truncate (first values) base))))
((< (first values) base) (nbutlast (cons (first values) (cons (second values) acc))))))
This works
[69]> (dec->ops 250 8)
(3 7 2)
[70]> (dec->ops 2500000 8)
(1 1 4 2 2 6 4 0)
I would go with the following implementation when trying to avoid recursion:
(defun digits-in-base (number base)
(check-type number (integer 0))
(check-type base (integer 2))
(loop
:with remainder
:do (multiple-value-setq (number remainder) (truncate number base))
:collect remainder
:until (= number 0)))
Multiple values are not directly handled by LOOP so instead of converting the values to a list I prefer using MULTIPLE-VALUE-SETQ to update multiple values at once.
The code first does some type checks because otherwise it can loop infinitely: the inputs are expected to be respectively positive or null, and greater than 1.
I put the :until condition at the end so that 0 gives (0).
Note that the digits are sorted from the smallest to the highest rank:
(digits-in-base 4 2)
=> (0 0 1)
(digits-in-base 250 8)
=> (2 7 3)
Alternatively, for the reverse order:
(defun digits-in-base (number base)
(check-type number (integer 0))
(check-type base (integer 2))
(loop
:with remainder :and digits
:do (multiple-value-setq (number remainder) (truncate number base))
:do (push remainder digits)
:until (= number 0)
:finally (return digits)))
(digits-in-base 4 2)
=> (1 0 0)
(digits-in-base 250 8)
=> (3 7 2)
In a previous version of this answer I said the first one (from low to high digits) is better for further manipulation of the digits, but I am not so sure.
Converting back to a number is quite easy with number arranged from high to low digits (all the code below use the second version):
(defun digits-to-number (digits base)
(reduce (lambda (n d) (+ d (* n base)))
digits
:initial-value 0))
So is formatting to a string:
(defun number-string-base (number base)
(format nil
(if (<= base 10)
"(~{~d~})~d"
"(~{~d~^'~})~d")
(digits-in-base number base)
base))
(number-string-base 250 8)
=> "(372)8"
(number-string-base 250 16)
=> "(15'10)16"
Since you expressed interest in various approaches, one thing worth remembering is that Lisp's great strength is creating and extending languages. Indeed all the iteration constructs in Common Lisp are such extensions: CL has no primitive iteration constructs at all.
So there is nothing preventing anyone writing their own, which will be just as good as the ones the language provides. For instance Tim Bradshaw's simple loops provides an 'applicative looping construct', looping, which makes this quite simple to implement:
(defun dec->ops (n base)
(looping ((m n)
(a '()))
(when (< (abs m) base)
(return (cons m a)))
(multiple-value-bind (q r) (truncate m base)
(values q (cons r a)))))
Using looping, the variables bound in the loop are updated by the values of the last form in the loop's body.
Of course this is rather close to the classic tail-recursive implementation (here using iterate):
(defun dec->ops (n base)
(iterate next ((m n)
(a '()))
(if (< (abs m) base)
(cons m a)
(multiple-value-bind (q r) (truncate m base)
(next q (cons r a))))))
People tend not to like things like this because they are 'not idiomatic CL' of course.
I'm arduously struggling my way through the N-queens problem in SICP (the book; I spent a few days on it -- last question here: Solving Eight-queens in scheme). Here is what I have for the helper functions:
#lang sicp
; the SICP language in Racket already defines this:
; (define nil '()
; boilerplate: filter function and range functions
(define (filter func lst)
(cond
((null? lst)
nil)
(else
(if (func (car lst))
(cons (car lst) (filter func (cdr lst)))
(filter func (cdr lst))))))
(define (range a b)
(if (> a b)
nil
(cons a (range (+ 1 a) b))))
; Selectors/handlers to avoid confusion on the (col, row) notation:
; representing it a position as (col, row), using 1-based indexing
(define (make-position col row) (cons col (list row)))
(define (col p) (car p))
(define (row p) (cadr p))
; adding a new position to a board
(define (add-new-position existing-positions p)
(append existing-positions
(list (make-position (col p) (row p)))))
; The 'safe' function
(define (any? l proc)
(cond ((null? l) #f)
((proc (car l)) #t)
(else (any? (cdr l) proc))))
(define (none? l proc) (not (any? l proc)))
(define (safe? existing-positions p)
(let ((bool (lambda (x) x)) (r (row p)) (c (col p)))
(and
; is the row safe? i.e., no other queen occupies that row?
(none? (map (lambda (p) (= (row p) r)) existing-positions)
bool)
; safe from the diagonal going up
(none? (map (lambda (p) (= r (+ (row p) (- c (col p)))))
existing-positions)
bool)
; safe from the diagonal going down
(none? (map (lambda (p) (= r (- (row p) (- c (col p)))))
existing-positions)
bool))))
And now, with that boilerplate, the actual/monstrous first working version I have of the queens problem:
(define (positions-for-col col size)
(map (lambda (ri) (make-position col ri))
(range 1 size)))
(define (queens board-size)
(define possible-positions '())
(define safe-positions '())
(define all-new-position-lists '())
(define all-positions-list '())
; existing-positions is a LIST of pairs
(define (queen-cols col existing-positions)
(if (> col board-size)
(begin
(set! all-positions-list
(append all-positions-list (list existing-positions))))
(begin
; for the column, generate all possible positions,
; for example (3 1) (3 2) (3 3) ...
(set! possible-positions (positions-for-col col board-size))
; (display "Possible positions: ") (display possible-positions) (newline)
; filter out the positions that are not safe from existing queens
(set! safe-positions
(filter (lambda (pos) (safe? existing-positions pos))
possible-positions))
; (display "Safe positions: ") (display safe-positions) (newline)
(if (null? safe-positions)
; bail if we don't have any safe positions
'()
; otherwise, build a list of positions for each safe possibility
; and recursively call the function for the next column
(begin
(set! all-new-position-lists
(map (lambda (pos)
(add-new-position existing-positions pos))
safe-positions))
; (display "All positions lists: ") (display all-new-position-lists) (newline)
; call itself for the next column
(map (lambda (positions-list) (queen-cols (+ 1 col)
positions-list))
all-new-position-lists))))))
(queen-cols 1 '())
all-positions-list)
(queens 5)
(((1 1) (2 3) (3 5) (4 2) (5 4))
((1 1) (2 4) (3 2) (4 5) (5 3))
((1 2) (2 4) (3 1) (4 3) (5 5))
((1 2) (2 5) (3 3) (4 1) (5 4))
((1 3) (2 1) (3 4) (4 2) (5 5))
To be honest, I think I did all the set!s so that I could more easily debug things (is that common?) How could I remove the various set!s to make this a proper functional-procedure?
As an update, the most 'terse' I was able to get it is as follows, though it still appends to a list to build the positions:
(define (queens board-size)
(define all-positions-list '())
(define (queen-cols col existing-positions)
(if (> col board-size)
(begin
(set! all-positions-list
(append all-positions-list
(list existing-positions))))
(map (lambda (positions-list)
(queen-cols (+ 1 col) positions-list))
(map (lambda (pos)
(add-new-position existing-positions pos))
(filter (lambda (pos)
(safe? existing-positions pos))
(positions-for-col col board-size))))))
(queen-cols 1 nil)
all-positions-list)
Finally, I think here is the best I can do, making utilization of a 'flatmap' function that helps deal with nested lists:
; flatmap to help with reduction
(define (reduce function sequence initializer)
(let ((elem (if (null? sequence) nil (car sequence)))
(rest (if (null? sequence) nil (cdr sequence))))
(if (null? sequence)
initializer
(function elem
(reduce function rest initializer)))))
(define (flatmap proc seq)
(reduce append (map proc seq) nil))
; actual
(define (queens board-size)
(define (queen-cols col existing-positions)
(if (> col board-size)
(list existing-positions)
(flatmap
(lambda (positions-list)
(queen-cols (+ 1 col) positions-list))
(map
(lambda (pos)
(add-new-position existing-positions
pos))
(filter
(lambda (pos)
(safe? existing-positions pos))
(positions-for-col col board-size))))))
(queen-cols 1 nil))
Are there any advantages of this function over the one using set! or is it more a matter of preference (I find the set! one easier to read and debug).
When you are doing the SICP problems, it would be most beneficial if you strive to adhere to the spirit of the question. You can determine the spirit from the context: the topics covered till the point you are in the book, any helper code given, the terminology used etc. Specifically, avoid using parts of the scheme language that have not yet been introduced; the focus is not on whether you can solve the problem, it is on how you solve it. If you have been provided helper code, try to use it to the extent you can.
SICP has a way of building complexity; it does not introduce a concept unless it has presented enough motivation and justification for it. The underlying theme of the book is simplification through abstraction, and in this particular section you are introduced to various higher order procedures -- abstractions like accumulate, map, filter, flatmap which operate on sequences/lists, to make your code more structured, compact and ultimately easier to reason about.
As illustrated in the opening of this section, you could very well avoid the use of such higher programming constructs and still have programs that run fine, but their (liberal) use results in more structured, readable, top-down style code. It draws parallels from the design of signal processing systems, and shows how we can take inspiration from it to add structure to our code: using procedures like map, filter etc. compartmentalize our code's logic, not only making it look more hygienic but also more comprehensible.
If you prematurely use techniques which don't come until later in the book, you will be missing out on many key learnings which the authors intend for you from the present section. You need to shed the urge to think in an imperative way. Using set! is not a good way to do things in scheme, until it is. SICP forces you down a 'difficult' path by making you think in a functional manner for a reason -- it is for making your thinking (and code) elegant and 'clean'.
Just imagine how much more difficult it would be to reason about code which generates a tree recursive process, wherein each (child) function call is mutating the parameters of the function. Also, as I mentioned in the comments, assignment places additional burden upon the programmers (and on those who read their code) by making the order of the expressions have a bearing on the results of the computation, so it is harder to verify that the code does what is intended.
Edit: I just wanted to add a couple of points which I feel would add a bit more insight:
Your code using set! is not wrong (or even very inelegant), it is just that in doing so, you are being very explicit in telling what you are doing. Iteration also reduces the elegance a bit in addition to being bottom up -- it is generally harder to think bottom up.
I feel that teaching to do things recursively where possible is one of the aims of the book. You will find that recursion is a crucial technique, the use of which is inevitable throughout the book. For instance, in chapter 4, you will be writing evaluators (interpreters) where the authors evaluate the expressions recursively. Even much earlier, in section 2.3, there is the symbolic differentiation problem which is also an exercise in recursive evaluation of expressions. So even though you solved the problem imperatively (using set!, begin) and bottom-up iteration the first time, it is not the right way, as far as the problem statement is concerned.
Having said all this, here is my code for this problem (for all the structure and readability imparted by FP, comments are still indispensable):
; the board is a list of lists - a physical n x n board, where
; empty positions are 0 and filled positions are 1
(define (queens board-size)
(let ((empty-board (empty-board-gen board-size))) ; minor modification - making empty-board available to queen-cols
(define (queen-cols k)
(if (= k 0)
(list empty-board)
(filter (lambda (positions) (safe? k positions))
; the flatmap below generates a list of new positions
; by 'adjoining position'- adding 'board-size' number
; of new positions for each of the positions obtained
; recursively from (queen-cols (- k 1)), which have
; been found to be safe till column k-1. This new
; set (list) of positions is then filtered using the
; safe? function to filter out unsafe positions
(flatmap
(lambda (rest-of-queens)
; the map below adds 'board-size' number of new
; positions to 'rest-of-queens', which is an
; element of (queen-cols (- k 1))
(map (lambda (new-row)
(adjoin-position new-row k rest-of-queens))
(enumerate-interval 1 board-size)))
(queen-cols (- k 1))))))
(queen-cols board-size)) ; end of let block
)
; add a column having a queen placed at position (new-row, col).
(define (adjoin-position new-row col rest-queens)
(let ((board-dim (length rest-queens))) ;length of board
; first create a zero 'vector', put a queen in it at position
; 'new-row', then put (replace) this new vector/column at the
; 'col' position in rest-queens
(replace-elem (replace-elem 1 new-row (gen-zero-vector board-dim)) col rest-queens)))
(define (safe? k positions) ; the safe function
(let ((row-pos-k (non-zero-index (item-at-index k positions)))) ; get the row of the queen in column k
(define (iter-check col rem) ;iteratively check if column 'col' of the board is safe wrt the kth column
(let ((rw-col (non-zero-index (car rem)))) ; get the row of 'col' in which a queen is placed
(cond ((= k 1) #t); 1x1 board is always safe
((= col k) #t); if we reached the kth column, we are done
; some simple coordinate geometry
; checks if the row of the queen in col and kth
; column is same, and also checks if the 'slope' of
; the line connecting the queens of the two columns
; is 1 (i.e. if it's a diagonal), if either is true,
; the kth queen is not safe
((or (= row-pos-k rw-col) (= (- k col) (abs (- row-pos-k rw-col)))) #f)
(else (iter-check (+ col 1) (cdr rem)))))) ; check the next column
(iter-check 1 positions))) ; start checking from the first column
; helper functions follow
(define (item-at-index n items) ; given a list, return the nth element
(define (iter idx rem)
(if (= idx n)
(car rem)
(iter (+ idx 1) (cdr rem))))
(iter 1 items))
(define (non-zero-index items)
; gives the first non-zero element from items - used for
; determining the row at which a queen is placed
(define (iter a rem)
(if (> (car rem) 0)
a
(iter (+ a 1) (cdr rem))))
(iter 1 items))
(define (empty-board-gen n) ; the empty board is n lists, each list with n zeros
(map (lambda (x) (map (lambda (y) 0) (enumerate-interval 1 n))) (enumerate-interval 1 n)))
(define (replace-elem new-elem pos items) ; replace item at position pos in items by new-elem, ultimately used for replacing an empty column with a column which has a queen
(define (iter i res rem)
(if (= i pos)
(append res (list new-elem) (cdr rem))
(iter (+ i 1) (append res (list(car rem))) (cdr rem)))) (iter 1 '() items))
(define (gen-zero-vector n) ; generate a list of length n with only zeros as elements
(define (iter a res)
(if (> a n)
res
(iter (+ a 1) (append res (list 0))))) (iter 1 '()))
(define (flatmap proc seq)
(accumulate append '() (map proc seq)))
(define (length items) ; not particularly efficient way for length of a list
(accumulate + 0 (map (lambda (x) 1) items)))
(define (accumulate op null-value seq)
(if (null? seq)
null-value
(op (car seq) (accumulate op null-value (cdr seq)))))
(define (enumerate-interval low high) ; a list of integers from low to hi
(define (iter a b res)
(if (> a b)
res
(iter (+ a 1) b (append res (cons a '())))))
(iter low high '()))
There are many ways to tackle this problem. I'll attempt to write a short and concise solution using Racket-specific procedures, explaining each step of the way. A solution using only the Scheme procedures explained in SICP is also possible, but it'll be more verbose and I'd argue, more difficult to understand.
My aim is to write a functional-programming style solution reusing as many built-in procedures as possible, and avoiding mutation at all costs - this is the style that SICP encourages you to learn. I'll deviate from the template solution in SICP if I think we can get a clearer solution by reusing existing Racket procedures (it follows then, that this code must be executed using the #lang racket language), but I've provided another answer that fits exactly exercise 2.42 in the book, implemented in standard Scheme and compatible with #lang sicp.
First things first. Let's agree on how are we going to represent the board - this is a key point, the way we represent our data will have a big influence on how easy (or hard) is to implement our solution. I'll use a simple representation, with only the minimum necessary information.
Let's say a "board" is a list of row indexes. My origin of coordinates is the position (0, 0), on the top-left corner of the board. For the purpose of this exercise we only need to keep track of the row a queen is in, the column is implicitly represented by its index in the list and there can only be one queen per column. Using my representation, the list '(2 0 3 1) encodes the following board, notice how the queens' position is uniquely represented by its row number and its index:
0 1 2 3
0 . Q . .
1 . . . Q
2 Q . . .
3 . . Q .
Next, let's see how are we going to check if a new queen added at the end of the board is "safe" with respect to the previously existing queens. For this, we need to check if there are any other queens in the same row, or if there are queens in the diagonal lines starting from the new queen's position. We don't need to check for queens in the same column, we're trying to set a single new queen and there aren't any others in this row. Let's split this task in multiple procedures.
; main procedure for checking if a queen in the given
; column is "safe" in the board; there are no more
; queens to the "right" or in the same column
(define (safe? col board)
; we're only interested in the queen's row for the given column
(let ([row (list-ref board (sub1 col))])
; the queen must be safe on the row and on the diagonals
(and (safe-row? row board)
(safe-diagonals? row board))))
; check if there are any other queens in the same row,
; do this by counting how many times `row` appears in `board`
(define (safe-row? row board)
; only the queen we want to add can be in this row
; `curry` is a shorthand for writing a lambda that
; compares `row` to each element in `board`
(= (count (curry equal? row) board) 1))
; check if there are any other queens in either the "upper"
; or the "lower" diagonals starting from the current queen's
; position and going to the "left" of it
(define (safe-diagonals? row board)
; we want to traverse the row list from right-to-left so we
; reverse it, and remove the current queen from it; upper and
; lower positions are calculated starting from the current queen
(let loop ([lst (rest (reverse board))]
[upper (sub1 row)]
[lower (add1 row)])
; the queen is safe after checking all the list
(or (null? lst)
; the queen is not safe if we find another queen in
; the same row, either on the upper or lower diagonal
(and (not (= (first lst) upper))
(not (= (first lst) lower))
; check the next position, updating upper and lower
(loop (rest lst) (sub1 upper) (add1 lower))))))
Some optimizations could be done, for example stopping early if there's more than one queen in the same row or stopping when the diagonals' rows fall outside of the board, but they'll make the code harder to understand and I'll leave them as an exercise for the reader.
In the book they suggest we use an adjoin-position procedure that receives both row and column parameters; with my representation we only need the row so I'm renaming it to add-queen, it simply adds a new queen at the end of a board:
; add a new queen's row to the end of the board
(define (add-queen queen-row board)
(append board (list queen-row)))
Now for the fun part. With all of the above procedures in place, we need to try out different combinations of queens and filter out those that are not safe. We'll use higher-order procedures and recursion for implementing this backtracking solution, there's no need to use set! at all as long as we're in the right mindset.
This will be easier to understand if you read if from the "inside out", try to grok what the inner parts do before going to the outer parts, and always remember that we're unwinding our way in a recursive process: the first case that will get executed is when we have an empty board, the next case is when we have a board with only one queen in position and so on, until we finally have a full board.
; main procedure: returns a list of all safe boards of the given
; size using our previously defined board representation
(define (queens board-size)
; we need two values to perform our computation:
; `queen-col`: current row of the queen we're attempting to set
; `board-size`: the full size of the board we're trying to fill
; I implemented this with a named let instead of the book's
; `queen-cols` nested procedure
(let loop ([queen-col board-size])
; if there are no more columns to try exit the recursion
(if (zero? queen-col)
; base case: return a list with an empty list as its only
; element; remember that the output is a list of lists
; the book's `empty-board` is just the empty list '()
(list '())
; we'll generate queen combinations below, but only the
; safe ones will survive for the next recursive call
(filter (λ (board) (safe? queen-col board))
; append-map will flatten the results as we go, we want
; a list of lists, not a list of lists of lists of...
; this is equivalent to the book's flatmap implementation
(append-map
(λ (previous-boards)
(map (λ (new-queen-row)
; add a new queen row to each one of
; the previous valid boards we found
(add-queen new-queen-row previous-boards))
; generate all possible queen row values for this
; board size, this is similar to the book's
; `enumerate-interval` but starting from zero
(range board-size)))
; advance the recursion, try a smaller column
; position, as the recursion unwinds this will
; return only previous valid boards
(loop (sub1 queen-col)))))))
And that's all there is to it! I'll provide a couple of printing procedures (useful for testing) which should be self-explanatory; they take my compact board representation and print it in a more readable way. Queens are represented by 'o and empty spaces by 'x:
(define (print-board board)
(for-each (λ (row) (printf "~a~n" row))
(map (λ (row)
(map (λ (col) (if (= row col) 'o 'x))
board))
(range (length board)))))
(define (print-all-boards boards)
(for-each (λ (board) (print-board board) (newline))
boards))
We can verify that things work and that the number of solutions for the 8-queens problem is as expected:
(length (queens 8))
=> 92
(print-all-boards (queens 4))
(x x o x)
(o x x x)
(x x x o)
(x o x x)
(x o x x)
(x x x o)
(o x x x)
(x x o x)
As a bonus, here's another solution that works with the exact definition of queens as provided in the SICP book. I won't go into details because it uses the same board representation (except that here the indexes start in 1 not in 0) and safe? implementation of my previous answer, and the explanation for the queens procedure is essentially the same. I did some minor changes to favor standard Scheme procedures, so hopefully it'll be more portable.
#lang racket
; redefine procedures already explained in the book with
; Racket equivalents, delete them and use your own
; implementation to be able to run this under #lang sicp
(define flatmap append-map)
(define (enumerate-interval start end)
(range start (+ end 1)))
; new definitions required for this exercise
(define empty-board '())
(define (adjoin-position row col board)
; `col` is unused
(append board (list row)))
; same `safe?` implementation as before
(define (safe? col board)
(let ((row (list-ref board (- col 1))))
(and (safe-row? row board)
(safe-diagonals? row board))))
(define (safe-row? row board)
; reimplemented to use standard Scheme procedures
(= (length (filter (lambda (r) (equal? r row)) board)) 1))
(define (safe-diagonals? row board)
(let loop ((lst (cdr (reverse board)))
(upper (- row 1))
(lower (+ row 1)))
(or (null? lst)
(and (not (= (car lst) upper))
(not (= (car lst) lower))
(loop (cdr lst) (- upper 1) (+ lower 1))))))
; exact same implementation of `queens` as in the book
(define (queens board-size)
(define (queen-cols k)
(if (= k 0)
(list empty-board)
(filter
(lambda (positions) (safe? k positions))
(flatmap
(lambda (rest-of-queens)
(map (lambda (new-row)
(adjoin-position new-row k rest-of-queens))
(enumerate-interval 1 board-size)))
(queen-cols (- k 1))))))
(queen-cols board-size))
; debugging
(define (print-board board)
(for-each (lambda (row) (display row) (newline))
(map (lambda (row)
(map (lambda (col) (if (= row col) 'o 'x))
board))
(enumerate-interval 1 (length board)))))
(define (print-all-boards boards)
(for-each (lambda (board) (print-board board) (newline))
boards))
The above code is more in spirit with the original exercise, which asked you to implement just three definitions: empty-board, adjoin-position and safe?, thus this was more of a question about data representation. Unsurprisingly, the results are the same:
(length (queens 8))
=> 92
(print-all-boards (queens 4))
(x x o x)
(o x x x)
(x x x o)
(x o x x)
(x o x x)
(x x x o)
(o x x x)
(x x o x)
I started programming with lisp yesterday so please excuse if I am making some really newbie mistake. I am trying to create a function which calculates the bell numbers using the bell triangle and my recursive triangle function is not working properly. I am also sure if I got my recursive triangle function working that my recursive bell function is somehow also broken.
When I test my triangle function I get the output:
(defun bell(l n)
(if(< n 1)(list 1))
(if (= n 1)(last l))
(bell (triangle (reverse l) (last l) (list-length l)) (- n 1))
)
(defun triangle(pL nL i)
(if(<= i 0)
(write "equals zero!")
(reverse nL)
)
(triangle pL (append (list (+ (nth i pL) (nth i nL))) nL) (- i 1))
)
(write (triangle '(1) '(1) 0))
=>
"equals zero!""equals zero!"
*** - NTH: -1 is not a non-negative integer
For some reason, it is printing my debug code twice even though the function should be meeting my base case on the first call.
For some reason, it is printing my debug code twice even though the function should be meeting my base case on the first call.
It is printed twice because if is not doing what you think it does. The first if test is true, therefore equals zero! is printed. After that, a recursive call to triangle function is invoked. The test is again true (-1 <= 0), so equals zero! is again printed. Finally, you get an error because nthcdr function is called with -1. I strongly recommend you a good lisp debugger. The one from Lispworks is pretty good.
I honestly don't get the logic of what you were trying to achieve with your code. so I wrote mine:
(defun generate-level (l &optional (result))
"given a list l that represents a triangle level, it generates the next level"
(if (null l) result
(if (null result)
(generate-level l (list (car (last l))))
(generate-level (cdr l) (append result
(list (+ (car l)
(car (last result)))))))))
(defun bell (levels &optional (l))
"generate a bell triangle with the number of labels given by the first parameter"
(unless (zerop levels)
(let ((to-print (if (null l) (list 1) (generate-level l))))
(print to-print)
(bell (1- levels) to-print))))
Things to understand the implementation:
&optional (parameter): this parameter is optional and nil by default.
append concatenates two lists. I'm using it to insert in the back of the list.
let ((to-print x)) creates a new variable binding (local variable) called to-print and initialized to x.
I almost forgot to mention how if works in common lisp:
(if (= x 1) y z) means if x is equal to 1 then return y, otherwise z.
Now if you call the function to create a Bell triangle of 7 levels:
CL-USER 9 > (bell 7)
(1)
(1 2)
(2 3 5)
(5 7 10 15)
(15 20 27 37 52)
(52 67 87 114 151 203)
(203 255 322 409 523 674 877)
NIL
It would be nicer to print it with the appropiate padding, like this:
1
1 2
2 3 5
5 7 10 15
15 20 27 37 52
52 67 87 114 151 203
203 255 322 409 523 674 877
but I left that as an exercise to the reader.
Your ifs don't have any effect. They're evaluated, and produce results, but then you discard them. Just like
(defun abc ()
'a
'b
'c)
would evaluate 'a and 'b to produce the symbols a and b, and then would evaluate 'c to produce the symbol c, which would then be returned. In the case of
(if(<= i 0)
(write "equals zero!") ; then
(reverse nL) ; else
)
you're comparing whether i is less than or equal to zero, and if it is, you print equals zero, and if it's not, you (non-destructively) reverse nL and discard the result. Then you finish the function by making a call to triangle. It seems like you probably want to return the reversed nL when i is less than or equal to zero. Use cond instead, since you can have multiple body forms, as in:
(cond
((<= i 0) (write ...) (reverse nL))
(t (triangle ...)))
You could also use if with progn to group the forms:
(if (<= i 0)
(progn
(write ...)
(reverse nL))
(triangle ...))
Your other function has the same problem. If you want to return values in those first cases, you need to use a form that actually returns them. For instance:
(if (< n 1)
(list 1)
(if (= n 1)
(last l)
(bell #| ... |#)))
More idiomatic would be cond, and using list rather than l, which looks a lot like 1:
(cond
((< n 1) (list 1))
((= n 1) (last list))
(t (bell #| ... |#)))
Thank you all for the explanations. I eventually arrived at the code below. I realized that the if block worked something like..
(if (condition) (execute statement) (else execute this statement))
(defun bell(l n)
(if (< n 2)(last l)
(bell (triangle l (last l) 0) (- n 1))
)
)
(defun triangle(pL nL i)
(if(= i (list-length pL)) nL
(triangle pL (append nL (list (+ (nth i pL) (nth i nL)))) (+ i 1))
)
)
(write (bell (list 1) 10))
I decided to write a function that given a number will return a list containing the digits in that number, my attempt is:
(define (rev-digits n)
(if (= n 0)
'()
(cons (modulo n 10) (digits (quotient n 10)))))
(define (digits n)
(reverse (rev-digits n)))
The fact is, I need the digits to be in proper order, but the function returns, for example:
> (digits 1234567890)
'(9 7 5 3 1 2 4 6 8 0)
In seemingly random order... can you help me getting a more ordinated output?
rev-digits needs to call itself, not digits.
(define (rev-digits n)
(if (= n 0)
'()
(cons (modulo n 10) (rev-digits (quotient n 10)))))
(define (digits n)
(reverse (rev-digits n)))
should work.
It's worth noting that your "random" output was not in fact random; rather the digits were "bouncing" back and forth from the start to the end of the list. Which makes sense, because you were effectively switching back and forth between a "normal" and reversed version of your digits function.
The answer given by #JayKominek is spot-on and fixes the error in your code. To complement it, here's an alternative implementation:
(define (rev-digits n)
(let loop ((n n) (acc '()))
(if (< n 10)
(cons n acc)
(loop (quotient n 10) (cons (modulo n 10) acc)))))
The advantages of the above code are:
It's tail recursive and hence more efficient
It correctly handles the edge case when n is zero (your code returns an empty list)
It doesn't require a helper procedure, thanks to the use of a named let
It builds the list in the correct order, there's no need to reverse it at the end
A simple solution:
#lang racket
(define (digits n)
(for/list ([c (number->string n)])
(- (char->integer c) (char->integer #\0))))
ive been given a task in Scheme (Dr Racket) to reverse to order of a given digit. The solution should be recursive, and this is what i got this far..
The truth is, im not quite sure if the given algorithm even works because i get:
" application: not a procedure;
expected a procedure that can be applied to arguments"
error every time i run it..
Any thoughts or help on the issue?
(define reverse-digits
(lambda (n) (if (> n 9)
(+ (* 10 (modulo n 10)) (reverse-digits (quotient n 10)))
(n))))
(reverse-digits 1234)
This is a HW assignment so I won't give you code.
Your problem is that multiplying (modulo n 10) by 10 doesn't get you to the position you need to be in. Consider (reverse-digits 123):
(reverse-digits 123)
(+ 30 (reverse-digits 12))
(+ 30 (+ 20 (reverse-digits 1)))
(+ 30 (+ 20 1))
51
What you want is to multiply it by a different power of 10 every time depending on the length of the number. You could either make a function that calculates the length of the number (possibly by repeatedly dividing the number by 10 and keeping track of how many times it did that) or passing along the length of the number (possibly by creating another function that takes the number n as an argument and calculates the length, then passes it along to your function which will then subtract 1 from length every recursive call.
What you would then get is something like this:
(reverse-digits 123)
(+ 300 (reverse-digits 12))
(+ 300 (+ 20 (reverse-digits 1)))
(+ 300 (+ 20 1))
321
The error you're getting is because in your else-case, you do (n). As n is not a procedure, you get an error. You just want n instead.
Are you bound to using specific procedures ? If not, there's an alternative to using modulo and adding numbers. It's about using list procedures such as
number->string
take
list->string
and so on.
This is my solution, it is not very efficient!
(define
invert-number-aux (λ (n res)
(if (empty? n) res
(invert-number-aux
(take n (-(length n) 1)) ;new n
(append res (list (last n))) ;new res
)
)))
(define
invert-number (λ (n)
(string->number (list->string (invert-number-aux (string->list(number->string n)) '())))
))
It will be helpful to use smaller helper functions.
Here is one way to split the task in smaller parts:
; number->digits : natural -> list-of-digits
(define (number->digits n)
...)
; digits->number : list-of-digits -> natural
(define (number->digits n)
...)
With these helpers you can write:
(define (reverse-number x)
(digits->number
(reverse
(number->digits x))))
Also - if you want to the error " application: not a procedure; expected a procedure that can be applied to arguments" replace (n) with n.
If you run your program in DrRacket, the application (n) ought to be colored red. The problem is that (42) means evaluate 42 and then call the result as if is a function. Since 42 is a number, you get the error.
Its important to understand that fixnums don't have just one representation and what the different digits are of a number might change with the base of its representation. Here is my take on it.
(define (number->digits number (base 10))
(let loop ((n number) (acc '()))
(if (zero? n)
acc
(let-values (((res rem) (quotient/remainder n base)))
(loop res (cons rem acc))))))
(define (list->number lst (base 10))
(foldl (lambda (x acc)
(+ (* acc base) x))
0
lst))
(define (reverse-digits number (base 10))
(list->number (reverse (number->digits number base))
base))
(number->string (reverse-digits #b100111 #b10) #b10) ; ==> "111001" (or 39 => 57 in base 10)
(number->string (reverse-digits #xebabefac #x10) #x10) ; ==> "cafebabe" (or 3953913772 => 3405691582 in base 10)
(number->string (reverse-digits 1234)) ; ==> 4321