I need to append a new item to the end of a list. Here is what I tried:
(define my-list (list '1 2 3 4))
(let ((new-list (append my-list (list 5)))))
new-list
I expect to see:
(1 2 3 4 5)
But I receive:
let: bad syntax (missing binding pair5s or body) in (let ((new-list (append my-list (list 5)))))
Your problem is mostly of syntactical nature. The let expression in Scheme has the form (let (binding pairs) body). In your example code, while you do have a binding that should work, you don't have a body. For it to work, you need to change it to
(let ((new-list (append my-list (list 5))))
new-list)
In my DrRacket 6.3 this evaluates to what you would expect it to: '(1 2 3 4 5).
A let makes a local variable that exists for the duration of the let form. Thus
(let ((new-list (append my-list '(5))))
(display new-list) ; prints the new list
) ; ends the let, new-list no longer exist
new-list ; error since new-list is not bound
Your error message tells you that you have no expression in the let body which is a requirement. Since I added one in my code it's allowed. However now you get an error when you try evaluating new-list since it doesn't exist outside the let form.
Here is the Algol equivalent (specifically in JS)
const myList = [1,2,3,4];
{ // this makes a new scope
const newList = myList.concat([5]);
// at the end of the scope newList stops existing
}
newList;
// throws RefereceError since newList doesn't exist outside the block it was created.
Since you already tried using define you can do that instead and it will create a variable in the global or function scope:
(define my-list '(1 2 3 4))
(define new-list (append my-list (list 5)))
new-list ; ==> (1 2 3 4 5)
Related
(define (getFirstFew lst)
(cond
((= (read) 0) '()) ;returns nothing
(else(cons (car lst)(getFirstFew (cdr lst)(- (read) 1))))))
That is my code above. So i'm trying to write a procedure that will get the first x elements (user gets to choose what x gets to be) from a list. For example, input 4 with (getFirstFew '(1 6 2 4 5)) will result in '(1 6 2 4).
My current problem with this is that with using read two times, it gets called twice and then breaks the program. Is there a way for me to store whatever the user inputs into a variable and then use that variable throughout the program? Or is there another solution to this problem?
Notice that you have to perform the read only once, and store the value for future reference. Normally we'd use a let for this, but given that we also have to iterate over the list and decrement x on each iteration, a named let will be more appropriate. Try this:
(define (getFirstFew lst)
(let loop ((lst lst) (x (read)))
(if (= x 0)
'()
(cons (car lst)
(loop (cdr lst) (- x 1))))))
It works as expected:
(getFirstFew '(1 6 2 4 5))
> 4
=> '(1 6 2 4)
I have a nested list: (def mylist '(+ '(+ 1 2) 3))
When I eval it, I get 6 as expected: (eval mylist)
How can I change the last element (3)? I'd like to get a list like this:
(+ (+ 1 2) 4)
I've tried
(list (butlast mylist) 4)
but it yields this:
((+ (+ 1 2)) 4)
i.e. the first part is nested in a list itself. How can I fix it? I'm building up that list datastructure recursively and at a later point I'll evaluate it via the eval function.
You can use the following:
(concat (drop-last mylist) '(4))
If I have a list and I map a lambda function over it how can I get a reference to the next or previous item while processing the current one?
(map (lambda (x) x) '(1 2 3))
How would I reference the previous or next element while processing x?
John McCarthy originally made maplist and it's defined in CL still and predates map(car). It's definition in Scheme would be something like:
(define (maplist fun lst)
(if (null? lst)
'()
(cons (fun lst) (maplist fun (cdr lst)))))
(maplist values '(1 2 3 4)) ; ==> ((1 2 3 4) (2 3 4) (3 4) (4))
It's slightly more difficult to get each element like map but if you need more than the first then it's perfect.
Start with your one list, construct two other lists, one 'shifted' right, and the other 'shifted' left. Like this:
(define (process func x)
(let ((to-front (cons 'front (reverse (cdr (reverse x)))))
(to-rear (append (cdr x) (list 'rear))))
(map func to-front x to-rear)))
Note that the stuff above with reverse is because map expects all lists to have the same length. So when adding to the front, you need to remove one from the tail.
Also, the provided func needs to accept three arguments.
> (process list '(a b c))
((front a b) (a b c) (b c rear))
You can always use map on two zipped lists, i.e.
(import (srfi srfi-1)) ; or use some zip implementation
(define a '(1 2 3 4 5))
(map (lambda (x) x)
(zip a
(append (cdr a) (list (car a)))))
which results in ((1 2) (2 3) (3 4) (4 5) (5 1)).
Of course, the above assumes "periodic" boundary conditions for the lists (you should modify the boundary conditions for your case).
And also you would need to modify the lambda to handle pairs of elements.
For simplicity let's take the case of two elements at a time -- the current and next one. So if you have (list 1 2 3), and a function that takes this and next args, you want it to be called with:
1 2
2 3
3 <some value, let's say 3>
You could write that concisely as:
(map f xs (append (drop xs 1) (list (last xs))))
However the drop and append-ing means that's not the fastest way to do it. Instead you could write a map-slide-pairs function to do it more directly:
#lang racket/base
(require racket/match)
;; map a list as "sliding pairs". For example:
;; (map-slide-pairs cons '(1 2 3)) ==> '((1 . 2)
;; (2 . 3)
;; (3 . 3))
(define (map-slide-pairs f xs #:last-val [last-val #f])
;; Concise implementation:
;; (map f xs (append (drop xs 1) (list (last xs)))))
;; Faster implementation:
(let loop ([xs xs])
(match xs
[(list) (list)]
[(list this) (list (f this (or last-val this)))]
[(list this next more ...) (cons (f this next)
(loop (cons next more)))])))
(module+ test
(require rackunit)
(check-equal? (map-slide-pairs cons '(1 2 3))
'([1 . 2][2 . 3][3 . 3]))
(check-equal? (map-slide-pairs cons '(1 2 3) #:last-val 100)
'([1 . 2][2 . 3][3 . 100])))
Hopefully you can see how to extend this and make a "map-slide-triples" function that would be called with the previous, current, and next elements of the list.
I want to write a function which outputs a list.
The function gets a list and outputs a new one. For example:
(0 0 1 2 2 1) -> (3 4 4 5 5 6)).
What it does is: the index+1 in the initial list is a value in the new list. And the that value is placed x times in the new list dependent on the value in the initial list.
(1 2) -> (1 2 2)
(0 3 0 3) -> (2 2 2 4 4 4)
So 3 is on the second position, the value is three so 2(2nd position) is placed 3 times in the new list.
I came up with this, which does not work
(defun change-list (list)
(setq newlist '(1 2 3))
(setq i 0)
(while (<= i (length list))
(if (= (nth i list) 0)
(concatenate 'list '0 'newlist)
(concatenate 'list '(i) 'newlist))
(+ i 1)
(remove 0 newlist)))
The problem is mainly the fact that it does not recognize new variables. It gave me these errors:
functions.lisp:27:26:
warning: Undefined function referenced: while
functions.lisp:31:2:
warning: Free reference to undeclared variable newlist assumed special.
warning: Free reference to undeclared variable i assumed special.
Is there someone who understands this?
We were able to solve it ourselves:
(defun change-list (a)
(loop for j from 1 to (length a) by 1 append
(loop for i from 1 to (nth (- j 1) a) by 1
collect j )))
It is part of a larger assignment, and we did not get much education on lisp, more like: do it in lisp.
Let's assume this is Common Lisp, I'll then list some problems in your code:
(defun change-list (list)
(setq newlist '(1 2 3))
SETQ does not declare variables, it just sets them.
(setq i 0)
(while (<= i (length list))
WHILE does not exist in Common Lisp.
(if (= (nth i list) 0)
(concatenate 'list '0 'newlist)
0 is not a list. Thus you can't concatenate it.
CONCATENATE does not have a side effect. What ever you do here is lost.
NEWLIST here is a symbol, not a list. Does not work.
(concatenate 'list '(i) 'newlist))
i is not a variable here. Putting it into a list will have no.
CONCATENATE does not have a side effect. What ever you do here is lost.
NEWLIST here is a symbol, not a list. Does not work.
(+ i 1)
The effect of the above is lost.
(remove 0 newlist)
The effect of the above is lost.
))
You can simplify your answer to this:
(defun change-list (list)
(loop for i in list and j from 1
append (loop repeat i collect j)))
Basically, just another way to do the same thing:
(defun change-list (x)
(let ((index 0))
(mapcon
#'(lambda (y)
(incf index)
(let ((z (car y)))
(unless (zerop z)
(make-list z :initial-element index)))) x)))
But may be useful for the purpose of learning / who knows what your professor expects.
I am trying to learn lisp, using emacs dialect and I have a question.
let us say list has some members, for which predicate evaluates to false. how do I create a new list without those members? something like { A in L: p(A) is true }. in python there is filter function, is there something equivalent in lisp? if not, how do I do it?
Thanks
These functions are in the CL package, you will need to (require 'cl) to use them:
(remove-if-not #'evenp '(1 2 3 4 5))
This will return a new list with all even numbers from the argument.
Also look up delete-if-not, which does the same, but modifies its argument list.
If you manipulate lists heavily in your code, please use dash.el modern functional programming library, instead of writing boilerplate code and reinventing the wheel. It has every function to work with lists, trees, function application and flow control you can ever imagine. To keep all elements that match a predicate and remove others you need -filter:
(-filter (lambda (x) (> x 2)) '(1 2 3 4 5)) ; (3 4 5)
Other functions of interest include -remove, -take-while, -drop-while:
(-remove (lambda (x) (> x 2)) '(1 2 3 4 5)) ; (1 2)
(-take-while (lambda (x) (< x 3)) '(1 2 3 2 1)) ; (1 2)
(-drop-while (lambda (x) (< x 3)) '(1 2 3 2 1)) ; (3 2 1)
What is great about dash.el is that it supports anaphoric macros. Anaphoric macros behave like functions, but they allow special syntax to make code more concise. Instead of providing an anonymous function as an argument, just write an s-expression and use it instead of a local variable, like x in the previous examples. Corresponding anaphoric macros start with 2 dashes instead of one:
(--filter (> it 2) '(1 2 3 4 5)) ; (3 4 5)
(--remove (> it 2) '(1 2 3 4 5)) ; (1 2)
(--take-while (< it 3) '(1 2 3 2 1)) ; (1 2)
(--drop-while (< it 3) '(1 2 3 2 1)) ; (3 2 1)
I was looking for the very same last night and came across the Elisp Cookbook on EmacsWiki. The section on Lists/Sequences contains filtering teqniques and show how this can be done with mapcar and delq. I had to mod the code to use it for my own purposes but here is the original:
;; Emacs Lisp doesn’t come with a ‘filter’ function to keep elements that satisfy
;; a conditional and excise the elements that do not satisfy it. One can use ‘mapcar’
;; to iterate over a list with a conditional, and then use ‘delq’ to remove the ‘nil’
;; values.
(defun my-filter (condp lst)
(delq nil
(mapcar (lambda (x) (and (funcall condp x) x)) lst)))
;; Therefore
(my-filter 'identity my-list)
;; is equivalent to
(delq nil my-list)
;; For example:
(let ((num-list '(1 'a 2 "nil" 3 nil 4)))
(my-filter 'numberp num-list)) ==> (1 2 3 4)
;; Actually the package cl-seq contains the functions remove-if and remove-if-not.
;; The latter can be used instead of my-filter.
Emacs now comes with the library seq.el, use seq-remove.
seq-remove (pred sequence)
"Return a list of all the elements for which (PRED element) is nil in SEQUENCE."
With common lisp, you can implement the function as follows:
(defun my-filter (f args)
(cond ((null args) nil)
((if (funcall f (car args))
(cons (car args) (my-filter f (cdr args)))
(my-filter f (cdr args))))))
(print
(my-filter #'evenp '(1 2 3 4 5)))
There are a ton of ways to filter or select stuff from a list using built-ins which are much faster than loops. The built-in remove-if can be used this way. For example, suppose I want to drop the elements 3 through 10 in list MyList. Execute the following code as an example:
(let ((MyList (number-sequence 0 9))
(Index -1)
)
(remove-if #'(lambda (Elt)
(setq Index (1+ Index))
(and (>= Index 3) (<= Index 5))
)
MyList
)
)
You will get '(0 1 2 6 7 8 9).
Suppose you want to keep only elements between 3 and 5. You basically flip the condition I wrote above in the predicate.
(let ((MyList (number-sequence 0 9))
(Index -1)
)
(remove-if #'(lambda (Elt)
(setq Index (1+ Index))
(or (< Index 3) (> Index 5))
)
MyList
)
)
You will get '(3 4 5)
You can use whatever you need for the predicate that you must supply to remove-if. The only limit is your imagination about what to use. You can use the sequence filtering functions, but you don't need them.
Alternatively, you could also use mapcar or mapcar* to loop over a list using some function that turns specific entries to nil and the use (remove-if nil ...) to drop nils.
It's surprising there's no builtin version of filter without cl or (or seq which is very new).
The implementation of filter mentioned here (which you see in the Elisp Cookbook and elsewhere) is incorrect. It uses nil as a marker for items to be removed, which means if you have nils in your list to start with, they're going to be removed even if they satisfy the predicate.
To correct this implementation, the nil markers need to be replaced with an uninterred symbol (ie. gensym).
(defun my-filter (pred list)
(let ((DELMARKER (make-symbol "DEL")))
(delq
DELMARKER
(mapcar (lambda (x) (if (funcall pred x) x DELMARKER))
list))))