I'm trying to do a list of pairs as a part of a homework assignment.
I tried doing (somewhere in the middle of a function)
(setq list1 (append list1 (cons n1 n2)))
And for some reason I don't understand, this works fine with the first pair, but as I try to append the second pair, this error pops up:
*** - APPEND: A proper list must not end with 2
How can I solve this?
So, continuing on this subject, thanks to the answer given, I was able to correct my problem. But a new one came up, and I think it is related with it. So, I have this function:
(defun action(state)
(let ((list_actions '())
(limNumActions (1- (list-length state)))
(limNumSubActions 0)
(numActions 0)
(numSubActions 0))
(loop for numActions from 0 to limNumActions do
(setq limNumSubActions (1- (list-length (nth numActions state))))
(loop for numSubActions from 0 to limNumSubActions do
(setq list_actions (append list_actions
(list (cons numActions numSubActions))))
(print 'list_actions)
(print list_actions)))))
I used the printfunction as a simple "debugger". It returns this:
LIST_ACTIONS
((0 . 0))
LIST_ACTIONS
((0 . 0) (0 . 1))
LIST_ACTIONS
((0 . 0) (0 . 1) (1 . 0))
LIST_ACTIONS
((0 . 0) (0 . 1) (1 . 0) (1 . 1))
NIL
And this is exactly the result I was expecting! Except for the NIL part... Can you understand why the list list_actions is NILat the end?
The code can be expressed more succintly as follows:
(defun action (state)
(let ((list-actions '()))
(loop for i from 0 for state-i in state do
(loop for j from 0 below (length state-i) do
(setf list-actions (append list-actions (list (cons i j))))
(print 'list-actions)
(print list-actions)))
list-actions))
If only the result is needed, it can be shorter (and less costly, because it doesn't use the expensive append function),
(defun action (state)
(loop for i from 0 for state-i in state append
(loop for j below (length state-i) collect (cons i j))))
append takes two lists, not a list and a single element. You need to put a list around the pair before using it in append.
Currently the pair is being taken as part of the list, which makes the list improper and causes the second append to fail since improper lists don't exactly have an end to append to.
I have tried to refine your example a bit + write a version which uses a different, but, IMO more idiomatic approach to the problem:
;; Your original version, but cleaned up a bit
(defun action (state)
(loop with list-actions = nil
with lim-num-actions = (1- (list-length state))
with lim-num-sub-actions = 0
for num-actions from 0 to lim-num-actions
do (setq lim-num-sub-actions (1- (list-length (nth num-actions state))))
(loop for num-sub-actions from 0 to lim-num-sub-actions
do (push (cons num-actions num-sub-actions) list-actions)
(format t "~&~s ~s" 'list-actions list-actions))
finally (return list-actions)))
;; A more traditional approach (if you want to use iteration)
(defun action (state)
(reverse
(loop for i in state
for j from 0
collect (cons j 0))))
;; Using a nice library to do iteration
(ql:quickload "iterate")
;; Note, you could do (in-package :iterate)
;; to lose `iterate:' prefix to make it even shorter
(defun action (state)
(iterate:iter
(iterate:for i #:on state)
(iterate:for j #:from 0)
(iterate:accumulate (cons j 0) #:by #'cons)))
;; Just another way to do this, using `reduce'
(reduce #'(lambda (a b)
(declare (ignore b))
(cons (cons (1+ (caar a)) 0) a))
(cdr (mapcar #'list '(1 2 3 4 5)))
:initial-value '((0 . 0)))
(action (mapcar #'list '(1 2 3 4 5)))
Related
I am trying to loop through some rectangles and put the x and y coordinates separately in a list. However the list I am trying to fill looks terrible, the code:
(setq sspnls (ssget '((0 . "LWPOLYLINE"))))
(while (= 1 (getvar 'cmdactive))
(command pause)
)
(setq pnlslength (sslength sspnls))
(setq xlist (list))
(setq ylist (list))
(setq pnlname(ssname sspnls 0))
(setq sssort (ssadd))
(setq tllr 0)
(while (< tllr pnlslength)
(setq pnlname(ssname sspnls tllr))
(Command "hatch" "S" pnlname "")
(setq xs (cadr (assoc 10 (entget pnlname)))); y cordinate
(setq ys (caddr (assoc 10 (entget pnlname)))); x cordinate
(setq xlist (cons xlist xs))
(setq ylist (cons ylist ys))
(setq tllr (+ tllr 1))
);while end
The xlist or y list comes out like:
((((nil . 12057.63625954) . 12057.63625954) . 10345.63625954) . 10345.63625954)
I need it to look like:
(12057.63625954 12057.63625954 10345.63625954 10345.63625954)
What am I doing wrong? Please note I am using Draftsight, I also used the append function but the append function does not work at all?
Thanks a lot for your help!
The main issue is that you are using the cons function to create a dotted pair of the list and the X & Y coordinate values, instead of pushing the X & Y coordinate values onto the head of the existing list.
For example, your code is doing this:
_$ (cons '(1 2 3 4) 5)
((1 2 3 4) . 5)
Instead of this:
_$ (cons 5 '(1 2 3 4))
(5 1 2 3 4)
In general, your code could be reduced to the following:
(if (setq sel (ssget '((0 . "LWPOLYLINE"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
ent (ssname sel idx)
enx (entget ent)
xls (cons (cadr (assoc 10 enx)) xls)
yls (cons (caddr (assoc 10 enx)) yls)
)
(command "_.hatch" "_S" ent "")
)
)
Note also that you are only retrieving the coordinates of the first polyline vertex - I'm unsure whether or not this is intentional.
Was a bit hesitant to try at first but CMS IntelliCAD turned out to be a good alternative for me. The free trial worked immediately, which was good to try it out before paying for it. All the features it offers are user-friendly and easy to work with, which was another win for me. Good job.
I am trying to use the ability to have multiple "then-expressions" for a conditional in cond but I've yet to be successful in that. The goal is to have a function take in a list and spit out the count.
(define (countInc aList)
(let ((count 0))
(lambda ()
(cond
[(= (length aList) 0) '()]
[(> (second aList) (first aList)) (set! count (+ count 1)) (countInc (rest aList))]
(else (countInc (rest aList)))))))
(check-expect (countInc '(1 2 3 4 5 6)) 5)
To explain, answer is 5 because 2 > 1, 3 > 2, 4 > 3, 5 > 4, and 6 > 5.
Notice that your base case is incorrect: you're returning an empty list, shouldn't we be returning the counter? By the way, your procedure is actually returning a lambda with no arguments, that's not what you want to do.
Also: you should never use length for determining if a list is empty, and in general you should avoid using set! unless strictly necessary - Scheme favors a functional-programming style.
What you want to do can be written without mutating state variables, the trick is to keep track of the previous element while traversing the list - and beware of the many edge cases!
(define (countInc lst)
; edge cases
(if (or (empty? lst) (empty? (rest lst)))
0
; use a named let or a helper procedure
(let loop ((prev (first lst))
(lst (rest lst)))
(cond ((empty? (rest lst)) ; base case
(if (> (first lst) prev) 1 0))
((> (first lst) prev) ; found one, count it
(+ 1 (loop (first lst) (rest lst))))
(else ; skip this one
(loop (first lst) (rest lst)))))))
This works fine even for the edge cases, I've provided tests for them:
(countInc '())
=> 0
(countInc '(1))
=> 0
(countInc '(2 1))
=> 0
(countInc '(1 2))
=> 1
(countInc '(4 1 3 2 5 6))
=> 3
(countInc '(1 2 3 4 5 6))
=> 5
****What I tried****
(define(help num)
(if(= num 1)
num
(cons(num (help( - num 1))))))
;i called this defination in the bottom one
(define (list-expand L)
(cond
[(empty? L)'()]
[(=(car L)1)(cons(car L)(list-expand (cdr L)))]
[(>(car L)1) (cons(help(car L)(list-expand(cdr L))))]))
In the help procedure, the base case is incorrect - if the output is a list then you must return a list. And in the recursive step, num is not a procedure, so it must not be surrounded by brackets:
(define (help num)
(if (<= num 0)
'()
(cons num (help (- num 1)))))
And in list-expand, both recursive steps are incorrect. You just need to test whether the list is empty or not, calling help with the correct number of parameters; use append to combine the results, because we're concatenating sublists together:
(define (list-expand L)
(if (empty? L)
'()
(append (help (car L)) (list-expand (cdr L)))))
That should work as expected, but please spend some time studying Scheme's syntax, you still have trouble with the basics, for instance, when and where to use brackets...
(list-expand '(3 2))
=> '(3 2 1 2 1)
Just for fun - a non-recursive solution in Racket:
(append-map (lambda (n) (stream->list (in-range n 0 -1))) '(3 2))
;; or:
(append-map (lambda (n) (for/list ((x (in-range n 0 -1))) x)) '(3 2))
Returning:
'(3 2 1 2 1)
I've just started learning Racket.
I have written this procedure:
#lang racket
(define split
(lambda (list)
(define plus-list '())
(define minus-list '())
(cond ((null? list) '())
(else
(do ([i (length list) (- i 1)])
((zero? i))
(define l (list-ref list i))
(define item (last-element-on-list l))
(cond ((= (cdr l '+)) (set! plus-list (cons list plus-list)))
((= (cdr l '-)) (set! minus-list (cons list minus-list))))
)
(cons plus-list minus-list)
)
)
)
)
And instead of using (list-ref lst i) inside de do I have defined a variable l:
(define (list-ref lst i) l)
But it seems that I cann't do that, because I get the error:
define: not allowed in an expression context in: (define l (list-ref
lst i))
But there are a lot of define inside the do.
If I remove all the define inside the do, I have to write a lot of code and it is not easier to read and understand:
(define split
(lambda (list)
(define plus-list '())
(define minus-list '())
(cond ((null? list) '())
(else
(do ([i (length list) (- i 1)])
((zero? i))
(cond ((= (cdr (last-element-on-list (list-ref list i)) '+)) (set! plus-list (cons (list-ref list i) plus-list)))
((= (cdr (last-element-on-list (list-ref list i)) '-)) (set! minus-list (cons (list-ref list i) minus-list))))
)
(cons plus-list minus-list)
)
)
)
)
How can I define a variable inside a do?
Reading your other question I see why you write the bolded expressions -
…
(cond ((= (cdr (last-element-on-list (list-ref list i)) '+))
(set! plus-list
(cons (list-ref list i) plus-list)))
((= (cdr (last-element-on-list (list-ref list i)) '-))
(set! minus-list
(cons (list-ref list i) minus-list))))
…
Your input list shown there is –
(define lst
'((n 25 f +)
(s 25 m +)
(ll 20 no -)))
Your split is inspecting the contents of each element of l. split has overstepped its boundaries and now it only works for lists containing elements of this particular structure. Along with set!, lack of else in a cond is typically an indication you're doing something wrong. You also call (cdr (last-element-of-list ...)). If last-element-of-list returns an atom, cdr would throw an error here.
Consider designing split in a more generic way –
(define (split proc l)
(define (loop l true false)
(cond ((null? l)
(cons true false))
((proc (car l))
(loop (cdr l)
(cons (car l) true)
false))
(else
(loop (cdr l)
true
(cons (car l) false)))))
(loop l '() '()))
(split (lambda (x) (> x 5))
'(1 5 3 9 7 0 8 3 2 6 4))
;; '((6 8 7 9) 4 2 3 0 3 5 1)
If our list contains different elements, we can still use the same split procedure –
(split (lambda (x) (eq? '+ (cadr x)))
'((1 +) (1 -) (2 +) (3 +) (2 -) (3 -) (4 +)))
;; '(((4 +) (3 +) (2 +) (1 +)) (3 -) (2 -) (1 -))
I think it's never too early to start learning continuation passing style. Below, return represents our continuation and defaults to cons, the same procedure we used to return the final result in our original implementation. Intuitively, a continuation represents "the next step" of the computation –
(define (split proc l (return cons)) ;; `return` is our continuation
(if (null? l)
;; base case: list is empty, return empty result
(return '() '())
;; inductive case: at least one `x`
(let* ((x (car l))
(bool (proc x)))
(split proc ;; tail recur with our proc
(cdr l) ;; ... a smaller list
(lambda (t f) ;; ... and "the next step"
(if bool ;; if `(proc x)` returned true
(return (cons x t) ;; ... cons the `x` onto the `t` result
f) ;; ... and leave the `f` the same
(return t ;; otherwise leave `t` the same
(cons x f)))))))) ;; ... and cons the `x` onto the `f` result
If we run our split procedure, you'll notice we get the same exact output as above. At first glance it looks like we made a mess of a nice program, however there's one distinct advantage of this implementation. Because the continuation is user-configurable, instead of cons, we could decide an entirely different fate for our two lists, t and f –
(split (lambda (x) (eq? '+ (cadr x)))
'((1 +) (1 -) (2 +) (3 +) (2 -) (3 -) (4 +))
(lambda (plus minus)
(printf "plus: ~a, minus: ~a\n" plus minus)))
;; plus: ((1 +) (2 +) (3 +) (4 +)), minus: ((1 -) (2 -) (3 -))
Note how plus and minus were given the respective results. We didn't have to pick apart an intermediate cons result. More intuitively, we want printf to be "the next step", but we only need to specify the first argument –
(split (lambda (x) (eq? '+ (cadr x)))
'((1 +) (1 -) (2 +) (3 +) (2 -) (3 -) (4 +))
(curry printf "plus: ~a, minus: ~a\n"))
;; plus: ((1 +) (2 +) (3 +) (4 +)), minus: ((1 -) (2 -) (3 -))
Now we've scratched the surface of functional style :D
do loops are not idiomatic Racket. They are inherited from Scheme, and for whatever reason, they don’t permit internal definitions. I have never once used a do loop in Racket, since the for comprehensions are more functional, and they’re just generally easier to work with. Plus, since they originate in Racket, not in Scheme, they support internal definitions as you’d expect.
You could write your split function using for/fold instead of do, which has the added advantage of not needing to use set! (and avoiding the quadratic access time of using list-ref instead of iterating through the list). I’m not completely sure what your split function is supposed to do, as even with the internal definition removed, it does not compile, but here’s my best guess at what you might be attempting to do:
(define (split lst)
(for/fold ([plus-lst '()]
[minus-lst '()])
([l (in-list lst)])
(define item (last l))
(cond
[(equal? item '+)
(values (cons l plus-lst) minus-lst)]
[(equal? item '-)
(values plus-lst (cons l minus-lst))]
[else
(values plus-lst minus-lst)])))
Aside from the obvious restructuring to use for/fold instead of do, this code also makes the following changes over your code:
It uses the built-in last function from racket/list to get the last element of a list.
It uses equal? instead of = to compare symbols, since = is specifically for comparing numbers.
It indents things properly and puts close parentheses in idiomatic locations.
I fixed your code using let, read documentation about let it's heavily used in Scheme/Racket. I haven't used Scheme lately so I couldn't explain it as well as it is in documentation.
Shortly it's local symbol definition/redefinition, and you can use symbol with value only in let body.
Short example on let
(define x 5)
(let ((x 10))
(display x)) # => 10
(display x) # => 5
(let ((y 1))
(display y)) # => 1
(display y) # = => (error) y: undefined
Your code fixed using let
(define split
(lambda (list)
(let ((plus-list '())
(minus-list '()))
(cond ((null? list) '())
(else
(do ([i (length list) (- i 1)])
((zero? i))
(let ((l (list-ref list i))
(item (last-element-on-list l)))
(cond ((= (cdr l '+)) (set! plus-list (cons list plus-list)))
((= (cdr l '-)) (set! minus-list (cons list minus-list))))))
(cons plus-list minus-list))))))
Trying to learn lisp, want to delete every nth. I only managed to delete the first (nth) element
(defun delete-nth (n list)
(if (zerop n)
(cdr list)
(let ((cons (nthcdr (1- n) list)))
(if cons
(setf (cdr cons) (cddr cons))
cons))))
I'd like to delete the next nth and so on
Also I tried this:
(defun remove-nth (list n)
(remove-if (constantly t) list :start n :end (+ 1 n)))
No idea how to start again
What I was thinking was concatenating, but I have no idea of how to keep track of my position.
Counting from 1 (changing to 0 is trivial):
(defun remove-every-nth (n list)
(loop for element in list
for index from 1
unless (zerop (rem index n))
collect element))
Also: Please indent your code correctly.
An alternative way to do the same thing:
(defun remove-all-nth (list period)
(remove-if
(let ((iterator 0))
(lambda (x)
(declare (ignore x))
(= 0 (mod (incf iterator) period)))) list))
(remove-all-nth '(1 2 3 4 5 6 7 8 9 0) 3)
; (1 2 4 5 7 8 0)
Perhaps a more academic recursive solution here:
(defun delete-nth (n list)
(labels ((rec (i list)
(cond ((null list) nil)
((= i 1) (rec n (cdr list)))
(t (cons (car list) (rec (1- i) (cdr list)))))))
(rec n list)))
But in real life I'd use the loop option above.