0

I'm new in Common Lisp. And recently started to learn it. And I have a little problem how to call one function in another? I have a function mrg and function my_eval. And how call this function mrg in my_eval by typing this for example (print (my_eval '(mrg '(1 1 2 1 2 1 3) '(5 3 3 1 2 2)))). I tried but I had some errors like it's not a real number or undefined function A. Please help me.

This is my code:

(defun mrg (w v)
  (merge 'list (sort w #'<) (sort v #'<) #'<))

(defun my_eval (A)
  (cond
    ((atom A) A)
    ((equal 'car (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
    ((equal 'cdr (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
    ((equal 'atom (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
    ((equal 'cons (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal 'list (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal 'equal (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal '* (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal '/ (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal '+ (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal '- (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal '= (car A))
     (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
    ((equal 'mrg    ))
    (T A)))

(print (my_eval '(mrg '(1 1 2 1 2 1 3) '(5 3 3 1 2 2))))
1
  • What is the intent behind the let bindings of A? Commented Sep 30, 2018 at 20:11

3 Answers 3

1

If looking at the other calls, the condition clause for 'mrg must be

((equal 'mrg (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))

A must be a list, since it failed the first cond-clause (atom A).

Since mrg requires in this implementation two arguments, like in this eval the built-in functions

`cons`
`list`
`equal`
`*`
`/`
`+`
`-`
`=`

also do, after copying the list A to the local symbol A (the (let ((A A)) ...) part), funcall is applied to the first element of the ist A (which is mrg) and then the two following elements in the list A are given as arguments for the mrg funcall-call:

  • namely (cadr A) (which is synonym to (second A)) and
  • (caddr A) (which is synonym to (third A)).

Since each of the arguments themselves can be atoms or other function calls or special forms, you have to wrap a my_eval call around them and evaluate each of the arguments.

-- This is by the way what always happens if you call Lisp functions - each argument (which is an expression) is evaluated fully for itself before handling over the result to the main function call.

(In contrast, in macro calls, the arguments are not evaluated by default like in the function calls. Instead, you have in the function body the full control over when each of the arguments will be evaluated or treated as a symbol).

In your comment to @blihp's answer, you quoted A ('A) twice in the let-form and this prevents A to be taken as the list which it stands for actually.

Another problem I see is that your my_eval doesn't look for quote and I am also not sure whether your my_eval implementation which is a very rudimentary implementation, can handle ' correctly. Thus in the test mrg call, I recommend to use (list 1 3 4 2 4 ...) instead of '(1 3 4 2 4 ...) to prevent further complications.

Sign up to request clarification or add additional context in comments.

1 Comment

Okay I got it. Thanks for your explanation.
1

You're close but both function definitions have minor issues. In the mrg function definition, you need to pass a form (i.e. parenthesize what you want to execute) after the function declaration:

(defun mrg (w v)
    (merge 'list (sort w #'<) (sort v #'<) #'<))

And your my_eval function is incomplete for the mrg condition:

(defun my_eval(A)
    (cond
        ((atom A) A)
        ((equal 'car    (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
        ((equal 'cdr    (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
        ((equal 'atom   (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)))))
        ((equal 'cons   (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal 'list   (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal 'equal  (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal '*      (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal '/      (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal '+      (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal '-      (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal '=      (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (my_eval (caddr A)))))
        ((equal 'mrg    (car A)) (let ((A A)) (funcall (car A) (my_eval (cadr A)) (merge 'list (sort A #'<) (sort A #'<) #'<))))
        (T A)
    )
) 

(it looks like you're still missing the action (i.e. another form) for the mrg test but I'm not sure what you wanted to do in this case)

4 Comments

Well I tried this ((equal 'mrg (let ('A 'A)(funcall (A)(my_eval(cadr A)(merge 'list (sort A #'<) (sort A #'<) #'<)))))) but I had an error. And added this ((equal 'mrg (funcall mrg ('A 'A)))) and had an error. And I don't know how to call this mrg in this line ((equal 'mrg )). Maybe I should to parse it somehow?
I've updated the code in my answer to include a listp test (since you're recursively calling my_eval, you need to test for this as well since it will be passed lists) and added the mrg action.
Everything after the "((atom A) A)" was/is already assuming A is a list (implicitly, since it isn't an atom), so adding a "(listp..." condition first prevents any of the clauses from ever firing - every possible input is covered in the first two conditions.
Thanks for the catch @DarrenRinger ... since another answer was already accepted, I just removed the listp condition. As you correctly pointed out it was incorrectly bypassing the rest of the cond.
0

Invalid number of arguments: (EQUAL MRG)

As other answers pointed out, there is an arity mistmatch: EQUAL takes 2 parameters but was called with 1 argument in (EQUAL MRG).

Notice also that you are duplicating code a lot.

In all cases, you compare the head of a list with a constant symbol, then you funcall it by giving it as arguments the result of calling my_eval to the first, and sometimes the second, elements of the same list. Basically, your code is doing this:

(apply (first list) (mapcar #'my-eval (rest list)))

The APPLY function takes a function designator and call it with an arbitrary number of arguments. Here, that list of arguments is the result of applying my_eval to each remaining elements in the list.

The differences with your code are:

  • You check each function in head position, which is good for safety and can be replicated with a list of authorized symbols.
  • You discard remaining arguments, if they exist (e.g. (+ 1 4 9) would evaluate to 5 under my_eval). IMHO, my_eval should rather fail loudly in that case, because that's probably not what anyone would expect.
  • Note also that the let which rebinds A to a local variable name A is not useful here.

If you want to retain that approach but remove some code duplication, you may try this; the following function should be called you determined the form to evaluate is a cons-cell.

(defun my-eval/apply (cons)
  (check-type cons cons)
  (destructuring-bind (head . tail) cons
    (let ((size (length tail))
          (arity (case head
                   ((car cdr atom) 1)
                   ((cons list equal * / + - = mrg) 2))))
      (cond
        ((not arity) (error "Unknown function ~a" head))
        ((= size arity) (apply head (mapcar #'my_eval tail)))
        (t (error
            "Arity mismatch: ~a takes ~d parameter~:p but was ~
             called with ~d argument~:p in ~s" head arity size cons))))))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.