Search code examples
functionschemeracketsymbolsquote

racket - how to use the elements of a list as a procedure (function)


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?


Solution

  • 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.