1

I am doing a program which accepts one list and two atoms and replace atom-1 with atom-2 if atom-1 appears in list.
I am doing programming in a text editor using an Ubuntu system

Below is my code:

#! /usr/bin/clisp

(defun my-replace (lst x y)
  (cond
    ((eq lst nil) nil)
    ((eq (cdr lst) nil) nil)
    ((eq (car lst) x) (setq (car lst) y))
    ( t (my-replace ((cdr lst) x y)))))

When I try to execute this, Clisp shows this error:

*** - SYSTEM::%EXPAND-FORM: (CDR LST) should be a lambda expression

I am beginner in Lisp.
Please tell me how to solve this error.

Jay
  • 9,585
  • 6
  • 49
  • 72
ojas
  • 2,150
  • 5
  • 22
  • 37
  • 2
    This could probably be closed as a duplicate of [Common lisp error: “should be lambda expression”](http://stackoverflow.com/q/2575819/1281433), or [lisp - should be a lambda expression](http://stackoverflow.com/q/22163216/1281433), or [Why does my lisp code give me …should be a lambda expression?](http://stackoverflow.com/q/26941771/1281433), or [lisp error: should be lambda expression](http://stackoverflow.com/q/23746775/1281433), or [list should be a lambda expression](http://stackoverflow.com/q/12561779/1281433), etc., all of which have the same underlying issue: `((...) ...)`. – Joshua Taylor Sep 23 '15 at 13:46
  • @JoshuaTaylor: the CLISP error message is also not that great... – Rainer Joswig Sep 24 '15 at 09:18

2 Answers2

8

First you should improve formatting and indentation:

(defun my-replace (lst x y)
  (cond
   ((eq lst nil) nil)
   ((eq (cdr lst) nil) nil)
   ((eq (car lst) x) (setq (car lst) y))
   (t (my-replace ((cdr lst) x y)))))

Let's look at the code:

(defun my-replace (lst x y)
; in Common Lisp you can write LIST instead of LST
; what are x and y? The naming is not very speaking.

  (cond
   ((eq lst nil) nil)

   ((eq (cdr lst) nil) nil)   ; why this clause?

   ((eq (car lst) x) (setq (car lst) y))
   ; instead of SETQ use SETF

   (t (my-replace ((cdr lst) x y)))))
                  ; here is a function call? why the extra parentheses

I would concentrate first on a version which is non-destructive. You try to write a version which destructively modifies the list. Don't. Create a new list with the replacements done.

If you want to write a destructive version, you can do that, but get the basics right, first.

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
2

Edit: This answer points out another obvious error in the snippet. The error in the title is becuase of the extra parens around (cdr lst) x y, making it ((cdr lst) x y), which only makes sense if (cdr lst) is a lambda expression, and can be called.


Normally, if one wants to bind something to a value, one uses set. setq is a special version of set, when the first argument is a qutoed value, so instead of writing (set 'horse 123), you would write (setq horse 123).

However, you don't want to bind a symbol to a value, you want to make an element of a list into a value. This is when you want to use setf.

(let ((lst (list 1 2 3)))
  (setf (car lst) 4)
  (princ lst)) ;; (4 2 3)

See this excellent answer for more info.

Community
  • 1
  • 1
MartinHaTh
  • 1,417
  • 1
  • 13
  • 25
  • 2
    You are modifying a literal list. Which in many programming languages, including Common Lisp, is generally not a good idea. Use `LIST` to create a fresh list, which can be modified without problems. – Rainer Joswig Sep 23 '15 at 10:35
  • This is all very good advice, and I know OP accepted, but this doesn't actually explain or address the **SYSTEM::%EXPAND-FORM: (CDR LST) should be a lambda expression** error at all. – Joshua Taylor Sep 23 '15 at 13:45
  • @JoshuaTaylor of course. Somehow I misread `(cdr lst)` as `(car lst)`. I included a note at the top of my answer. – MartinHaTh Sep 23 '15 at 14:20
  • @MartinHaTh The edit is an improvement (since it mentions the actual error). I'm not sure I follow you about misreading (cdr list) as (car list); the same error would happen with `((car list) ...)` as with `((cdr list) ...)`. – Joshua Taylor Sep 23 '15 at 14:26
  • 1
    @JoshuaTaylor I though the error was for the line above (with the `setq`). Didn't even spot the extra parens :P – MartinHaTh Sep 23 '15 at 14:27
  • @MartinHaTh Ah, understood. – Joshua Taylor Sep 23 '15 at 14:30