VansFannel
VansFannel

Reputation: 45921

Run a function whose name is in a list

I'm still learning Racket.

I have to call an unknown function. The function and its parameters are in the following list:

(define l1 '((function-name parameter1)
(function-name parameter3)))

To run that function, I'm doing:

(first (car l1)) (second (car l1)) another-parameter

But I get the error:

 application: not a procedure;
 expected a procedure that can be applied to arguments
  given: 'function-name
  arguments...:

How can I run that function-name?

UPDATE:

I have tried Óscar's answer:

(eval (first (car l1)) (second (car l1)) another-parameter)

And I get the error:

 eval: arity mismatch;
 the expected number of arguments does not match the given number
  given: 3
  arguments...:

I have also tried:

(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))
(eval (first (car l1)) (second (car l1)) another-parameter ns)

And I get the same error:

 eval: arity mismatch;
 the expected number of arguments does not match the given number
  given: 4
  arguments...:

Then, I tried this:

(eval (list (first (car l1)) (second (car l1)) another-parameter))

And I get the error:

function-name: unbound identifier;
 also, no #%app syntax transformer is bound in: function-name

Finally, I have tried:

(eval (list (first (car l1)) (second (car l1)) another-parameter) ns)

And I get an internal error from function-name. But this function, works perfectly.

function-name could be at least three functions (or more), this is why I haven't put it here before. All of them will have two lists as parameters, and they will return #t or #f.

One of then, then one is testing now is:

(define match (lambda (list1 list2) ...))

Obviously, list1 and list2 are lists.

UPDATE 2:
I have tried Óscar's Minimal, Complete and verifiable example, and it works. But, I have modified to used on my on work, and it doesn't work. Look:

(define function-name
  (lambda (list1 list2)
    (append list1 list2)))

(define parameter1 '(1 2))
(define parameter3 '(3 4))
(define another-parameter '(5 6))

(define l1 '((function-name parameter1)
             (function-name parameter3)))

(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))

(define another-function
  (lambda (l1 the-parameter)
    (cond
      [(eval (list (first (car l1)) (second (car l1)) 'the-parameter) ns) l1])
  )
)

(another-function l1 another-parameter)

I have created another-function, and it fails with the parameter 'the-parameter. It complains saying:

the-parameter: undefined;
 cannot reference an identifier before its definition

So the problem is when I use a function's parameter as a parameter for the eval function.

Upvotes: 0

Views: 114

Answers (2)

Óscar López
Óscar López

Reputation: 236004

You can use eval and quasiquoting for this, it works for your input. Do notice that this is how you should post your questions, it's a Minimal, Complete, and Verifiable example that anyone can copy and run, without having to guess what you were thinking:

(define function-name
  (lambda (list1 list2)
    (append list1 list2)))

(define parameter1 '(1 2))
(define parameter3 '(3 4))
(define another-parameter '(5 6))

(define l1 '((function-name parameter1)
             (function-name parameter3)))

(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))

(define another-function
  (lambda (l1 the-parameter)
    (cond
      [(eval `(,(first (car l1)) ,(second (car l1)) ',the-parameter) ns)
       l1])))

(another-function l1 another-parameter)
=> '((function-name parameter1) (function-name parameter3))

Upvotes: 2

Sylwester
Sylwester

Reputation: 48745

Please consider evaluating the procedure like this:

(define l1 `((,sin ,(+ 1 2))
             (,+ 1 2 3)))

(sin (+ 1 2))                 ; ==> 0.14..
((caar l1) (cadar l1))        ; ==> 0.14..
(apply (caar l1) (cdar l1))   ; ==> 0.14..

(+ 1 2 3)                     ; ==> 6
(apply (caadr l1) (cdadr l1)) ; ==> 6

Why does this work? Well. Your attempted to call the name of a procedure. By evaluating the procedure name you get the actual procedure object. You can indeed evaluate a procedure in the REPL and see what you get back:

+  ; ==> #<procedure:+>
l1 ; ==> ((#<procedure:sin> 3) (#<procedure:+> 1 2 3))

If l1 were defined as '((sin (+ 1 2)) (+ 1 2 3)) evaluating it would return ((sin (+ 1 2)) (+ 1 2 3)) so there is a big difference.

And of course. Using the quasiquote/unquote is just a fancy way of writing this:

(define l1 (list (list sin (+ 1 2))
                 (list + '1 '2 '3)))

Upvotes: 4

Related Questions