Reputation: 3
I have a list that contains the "names" of some functions (for example '(+ - *)
)
I want to use that list to call the functions
(define list_of_names_of_functions '(+ - *))
(define sum (car list_of_names_of_functions))
(sum 2 3)
However, sum is a list, so can't be used as a procedure.
How should i do it?
Upvotes: 0
Views: 1157
Reputation:
As I mentioned in a comment, using eval
is not the right answer to this: it 'works' but it opens the way to horrors.
If you have a symbol like +
and you want to get its dynamic value then the Racket approach to doing this is to use namespaces. A namespace is really a machine which turns symbols into values in the same way that eval
does, but that's all it does, unlike eval
. Unfortunately I don't understand namespaces very well, but this will work:
(define-namespace-anchor nsa)
(define ns (namespace-anchor->namespace nsa))
(define (module-symbol-value s (in ns))
(namespace-variable-value s #t #f in))
Then
(define function-names '(+ - / *))
(define sum (module-symbol-value (first function-names)))
And now
> (sum 1 2 3)
6
> (eq? sum +)
#t
>
The problem with this approach is that it's leaky: if you have something like this:
(module msv racket
(provide module-symbol-value)
(define-namespace-anchor nsa)
(define ns (namespace-anchor->namespace nsa))
(define secret "secret")
(define (module-symbol-value s (in ns))
(namespace-variable-value s #t #f in)))
(require 'msv)
(define oops (module-symbol-value 'secret))
Now oops
is secret
. A way around this is to use make-base-namespace
to get a namespace which is equivalent to racket/base
.
Upvotes: 0
Reputation: 71065
The simple and immediate fix is to use (define list_of_functions (
list
+ - *))
, then with (define sum (car list_of_functions))
it will work.
(edit:) This happens because list
is a function which evaluates its argument(s) and returns the results in a list. Whereas quote
(or '
in front of an expression) prevents its argument from being evaluated.
'(A B ...)
is equivalent to (quote (A B ...))
; that (A B ...)
thing is a list of symbols, and quote preserves it as such.
It is a list of symbols because this is how Lisp code is read, either from a source file or from the REPL, i.e. at the interpreter's prompt. Other languages have their code as strings in a source code file, and compiler is some external magic which lives and works completely outside of the language. In Lisp-like languages, code is data. Code is read from textual source code file as (i.e. strings are turned into) nested lists of symbols, and explicit eval
, as well as implicit evaluation, is deep inside the language itself.
Thus what you had is equivalent to the list
(define list_of_names (list '+ '- '*))
which contains unevaluated symbols, as opposed to the list
(define list_of_functions (list + - *))
which contains their values, which happen to be the usual built-in functions denoted by those "names".
And we can call a function, but we can't call a symbol (not in Scheme anyway).
Upvotes: 1
Reputation: 48745
The variable list_of_names_of_functions
has symbol representation and not the actual function. you should perhaps make an alist with name and function like this:
(define ops `((+ . ,+) (- . ,-) (* . ,*)))
If you evaluate ops
you'll see something like:
((+ . #<procedure:+>)
(- . #<procedure:->)
(* . #<procedure:*>))
There is no standard on how a function/procedure object should be represented, but it is expected that that value can be applied as any other function:
((cdar ops) 1 2) ; ==> 3
Thus you can search for +
using:
(assq '+ ops)
; ==> (+ . #<procedure:+>)
(assq '/ ops)
; ==> #f
Thus if the result is truthy the cdr
will contain a procedure:
(apply (cdr (assq '+ ops)) '(1 2)) ; ==> 3
If you are making a special kid of eval
then you would consider the list an environment and it can easily be added to such that you can add /
. You can also supply anything callable so an op doesn't need to exist in the host system. eg. `(square . ,(lambda (v) (* v v))
works as well.
Consider using the naming convention of Scheme (and Lisp). Eg. instead of list_of_names_of_functions
it should be named list-of-names-of-functions
Upvotes: 1
Reputation: 3
I have just found the answer, sorry.
Solution will be to use the "eval" function
(define list_of_names_of_functions '(+ - *))
(define sum (car list_of_names_of_functions))
((eval sum) 2 3)
Upvotes: 0