LuXxenatorX
LuXxenatorX

Reputation: 137

Passing a function as an argument - lambda expression error?

I am trying to create a function that accepts a list and a function as parameters and applies that function to each element in the List. Here is my attempt:

(defun filter(fn L)
  (if (eq 0 (length L))
      (print "list empty")
      (print (mapcar (lambda (n) (#'fn n)) L))))
(print (filter #'evenp '(1 2 2 3 4)))

here is a second attempt:

(defvar R nil)
(defun filter(fn L)
  (if (eq 0 (length L))
      nil
      (cons (R (funcall fn (car L)) filter(fn (cdr L))))))
(print(filter #'evenp '(1 2 2 3 4)))

But for some simply confusing and unexplainable reason, I get following error for the first one:

#'FN should be lambda expression.

and this one for the second:

Undefined function R

I have tried so many things but nothing has worked so far.

Edit:: Thank you for the help so far. This:

(defun filter(fn L)
  (if (eq 0 (length L))
      (print "list empty")
      (remove-if-not #'fn '(1 2 3 4 5))))

(print (filter #'evenp '(1 2 2 3 4)))

This should do it. But I am still getting the

Undefined function FN

error. What to do???

Upvotes: 2

Views: 1401

Answers (2)

sds
sds

Reputation: 60064

How to do what you want

filter is called remove-if-not in Common Lisp:

(remove-if-not #'evenp '(1 2 3 4 5))
==> (2 4)

What is wrong with your code - syntactically

First Attempt

When you try to call a function stored in a variable (or passed into a function as a parameter), you need to use funcall or apply:

(mapcar (lambda (n) (funcall #'fn n)) L)

or just pass it along to mapcar:

(mapcar fn L)

Second Attempt

This is a total mess. You need to learn Common Lisp syntax, there are many nice books (see want to learn common lisp).

The specific problem is that R is in a function position (first list element) but it is not defined as a function - it is a variable. Even if you fix this problem, there are more problems there. You should read a book and then work it out yourself, it will be a useful exercise.

Basically, in Common Lisp parentheses are meaningful. E.g., in C you can write x+y, (x+y), (x)+(y) &c and they all mean the same. In Common Lisp R, (R), ((R)) &c are very different.

Third Attempt ("edit")

(defun filter(fn L)
  (if (eq 0 (length L))
      (print "list empty")
      (remove-if-not #'fn '(1 2 3 4 5))))

Here you have a variable fn, but you are using it as if it were a function (#'fn).

You need to do

      (remove-if-not fn '(1 2 3 4 5))

instead.

What is wrong with your code - semantically

No need for print

First, print is virtually never the right function to use in code. Use princ, prin1 or write instead.

Second, Common Lisp REPL stands for Read-Eval-Print Loop, so you do NOT need to print the return value of your function explicitly.

Follow the coding conventions

You write your code for others (including yourself 6 months down the road) to read, not just for a computer to run. If you follow the conventions, including naming your variables and functions, parentheses placement, indentation &c, you make your code more readable.

Compare with 0 using zerop

Write (zerop X) instead of (eq 0 X) (actually, you should use eql for numbers, but this is getting too hairy for now).

length can be expensive

Do not scan the whole list if all you need to know is whether it is empty. IOW,

(if (zero (length l))
    (print "the list is empty")
    (mapcar ... l))

is better written as

(if (null l)
    (print "the list is empty")
    (mapcar ... l))

Upvotes: 9

Joshua Taylor
Joshua Taylor

Reputation: 85913

#'FN should be lambda expression.

You've got (fn (cdr L)) in your code, and fn can't be called like that. Just like earlier in that line, you need to do (filter fn (cdr L)), not filter(fn (cdr L)).

Undefined function R

Same thing here. You've got (cons (R ...)) where you're trying to call R as a function, but it's not. It's not really clear to me what you're trying to do with R, so I can't really offer any help there.

Upvotes: 2

Related Questions