Writing a test function leveraging two namespaces in lisp

111 Views Asked by At

I started to learn Lisp and using Lispworks personal edition 6.1.1 and I hit on problem when evaluating basic functions. I am able to get them right in Scheme but they are not working when I try to evaluate them in Lisp.

I know in Lisp that every symbol has two namespaces. So I tried to write simple procedure for composing two procedures. It is working perfectly in Scheme but in Lisp there is a problem with evaluation.

Code in scheme it is working perfectly and return 2

(define (comp a b)
  (lambda (x)
    (a (b x))))

(define test (comp car cdr))
(test '(1 2 3))

Same code rewritten in Lisp

(defun comp (a b)
  (lambda (x)
    (funcall a (funcall b x))))

(defun test (comp #'car #'cdr))

(funcall test '(1 2 3))

Error in lispworks is:

Trying to bind a non-symbol, (FUNCTION CAR).

so when I try to evaluate (defun test (comp #'car #'cdr)) in listener I get

Non-symbol (FUNCTION CAR) used as variable name in function TEST.

I do not understand why it is not working written like that. I would aprreciate any help

4

There are 4 best solutions below

0
On BEST ANSWER

defun is used to define a function with parameters:

defun function-name lambda-list [[declaration* | documentation]] form*

so it requires a lambda list after the function name, but you have written:

(defun test (comp #'car #'cdr))

which does not respect this syntax. If you want to define a variable that contains the function resulting from composing two functions you have several possibilities:

  1. Use a special variable:

    (defvar test (comp #'car #'cdr))
    
  2. Use a local variable inside a form:

    (let ((test (comp #'car #'cdr)))
      (funcall test '(1 2 3))
    

You can even assign it to a global function name, like in:

(setf (symbol-function 'test) (comp #'car #'cdr)

and in this case you can use the name as a regular function name, without funcall:

(test '(1 2 3))
0
On

With local functions:

CL-USER 1 > (flet ((comp (a b)
                     (lambda (x)
                       (funcall a (funcall b x)))))
              (let ((test (comp #'car #'cdr)))
                (flet ((test (x)
                         (funcall test x)))
                  (test '(1 2 3)))))
2

CL-USER 2 > (labels ((comp (a b)
                       (lambda (x)
                         (funcall a (funcall b x))))
                     (test (x)
                       (funcall (comp #'car #'cdr) x)))
              (test '(1 2 3)))
2
0
On
(defun test (comp #'car #'cdr))

DEFUN expects a lambda-list after the name, and here your lambda-list is malformed since #'car is not a symbol but reads as (function car).

What you probably wanted to do is to define the function test as the composition of car and cdr; (comp ...) would return the appropriate function object but defun does not allow to have a value in place of the lambda-list.

You could do:

(setf (symbol-function 'test)
      (comp #'car #'cdr))
0
On

Another suggestion:

(defun comp (a b)
  (lambda (x)
     (funcall a (funcall b x))))

(defun mytest (x &key test)  ;; a "test" key is common
   (funcall test x))

(mytest '(1 2 3) :test (comp #'car #'cdr))

or

(defun comp (x a b)
  (funcall a (funcall b x)))

(defun test (x a b)
  (comp x a b))

(test '(1 2 3) #'car #'cdr)