Question on eval and modules

I was trying to make a simple video showing how it was easy to take a list of numbers '(1 2 3 4 5) and create a list like the following

(
(define (plus-1 n) (+ 1 n))
(define (plus-2 n) (+ 2 n))
)

in the context of a REPL, you apply eval over that list and boom, all the functions are there. Of course, in the context of a module, that doesn't work. And I totally understand why. Also, I get you could use macros to do this, but that is a distraction from this point.

What I want to know is there a way to load a list, syntax object, string? as if it was a source file? I have hit a wall with the documentation.

I know that the above list isn't enough for a module as there are no provides and so on.

Thanks.

Hi, @ndykman.

Apologies, if I am misunderstanding the thrust of the question, but is this kind of what you want to do?

I was confused about namespaces the first time I tried to use eval, which might be the case here also.

#lang racket/base

(define (make-defines lon)
  (for/list ([x (in-list lon)])
    (define name (string->symbol (format "plus-~a" x)))
    `(define (,name n) (+ ,x n))))

(define-namespace-anchor ns)

(define lon        '(1 2 3 4 5))
(define the-defines (make-defines lon))
(for-each println the-defines)

(parameterize ([current-namespace (namespace-anchor->namespace ns)])
  (eval
   `(begin ,@the-defines (println (plus-1 3)))))

;=>
'(define (plus-1 n) (+ 1 n))
'(define (plus-2 n) (+ 2 n))
'(define (plus-3 n) (+ 3 n))
'(define (plus-4 n) (+ 4 n))
'(define (plus-5 n) (+ 5 n))
4

I hope that helps!

For some added flavour, considering what you ask about reading file content, one might imagine the following scenario:

(define file-content
;; this is a `here-string' but for argument's sake we read this from a file
#<<qqq
(define x 1)
(define y 2)

(printf "x + 1 = ~a\n" (+ x 1))
(printf "y + 2 = ~a\n" (+ y 2))
qqq
)

(define data
  (parameterize ([current-input-port (open-input-string file-content)])
    (let reader ()
      (define datum (read))
      (cond
        [(eof-object? datum) null]
        [else
         (cons datum (reader))]))))

(parameterize ([current-namespace (namespace-anchor->namespace ns)])
  (eval `(begin ,@data)))

;=>
x + 1 = 2
y + 2 = 4

Of course, there are actual ways of creating languages and readers and so on which are more sophisticated.

Off the top of my head, Beautiful Racket or Reader Extensions (in the docs), for example, might be useful if you find yourself heading in that direction.

A note on reading and evaling from a file: consider setting (strict) sandbox limits on time, memory, and system access.

1 Like

Do you mean "evaluate" rather than "load" here?

In Racket/Scheme the function load reads expressions from a file and evaluates them as if they had been entered into a repl. The function load is a relic from the times past (over 20 years by now) before a proper module was added.

To evaluate an expression, use eval. Note that if you use eval from a module you need to provide a namespace as the second argument. This is normally trips up first time users of eval.

Also, someone needs to link to it, so I'll do it this time :wink:

1 Like

Thanks for the code and the links. I will chase those down.

Nobody misunderstood the question. I should have been more clear that was I was seeking was more information so I can ask a better question! This was me coming back to the Scheme/Racket (heck programming) after a long break and not knowing what I don't know, so to speak.

I should have been more clear that I completely understand that the old school just doesn't work. Running any old code is just a security and maintenance nightmare. This was for educational purposes (people are making content about programming after all) and I wanted to be able to explain how one could go about this in a more robust way.

As an aside, more developers are asking about metaprogramming due to Rust and comptime features in Zig, so the overall concept is being discussed more in certain circles. And the main question "what is metaprogramming?" and nowadays, that's a more interesting question than ever.

Nathan