0

I have LISP written in JavaScript (https://jcubic.github.io/lips/ with online demo where you can try it) and I have macro like this:

(define-macro (globalize symbol)
  (let ((obj (--> (. lips 'env) (get symbol))))
    `(begin
       ,@(map (lambda (key)
                (print (concat key " " (function? (. obj key))))
                (if (function? (. obj key))
                    (let* ((fname (gensym))
                           (args (gensym))
                           (code `(define (,(string->symbol key) . ,args)
                                    (apply (. ,obj ,key) ,args))))
                      (print code)
                      code)))
              ;; native Object.key function call on input object
              (array->list (--> Object (keys obj)))))))

In this code I use this:

(let ((obj (--> (. lips 'env) (get symbol))))

and I call this macro using:

(globalize pfs)

to create function for each static method of pfs (which is LightingFS from isomorphic-git where each function return a promise, it's like fs from node).

But it will not work for something like this:

(let ((x pfs))
  (globalize x))

because lips.env is global enviroment.

So my question is this how macro should work? Should they only process input data as symbols so they never have access to object before evaluation of lisp code?

How the LISP macro that generate bunch of functions based on variable should look like. For instance in scheme if I have alist in variable and want to generate function for each key that will return a value:

input:

(define input `((foo . 10) (bar . 20)))

output:

(begin
  (define (foo) 10)
  (define (bar) 20))

Can I write macro that will give such output if I use (macro input)? Or the only option is (macro ((foo . 10) (bar . 20)))?

I can accept generic Scheme or Common LISP answer but please don't post define-syntax and hygienic macros from scheme, My lisp don't have them and will never have.

The problem seems to be that I want to access value at macro expansion time and it need to have the value that in runtime. And second question Is eval in this case the only option?

This works in biwascheme:

(define-macro (macro obj)
  (let ((obj (eval obj)))
    `(begin
       ,@(map (lambda (pair)
                (let ((name (car pair))
                      (value (cdr pair)))
                `(define (,name) ,value)))
              obj))))

(define input `((foo . 10) (bar . 20)))

(macro input)

(foo)
;; ==> 10
(bar)
;; ==> 20

(in my lisp eval don't work like in biwascheme but that's other issue).

but this don't work, because x is not global:

(let ((x '((g . 10)))) (macro x))

Is macro with eval something you would normally do, or should them be avoided? Is there other way to generate bunch of functions based on runtime object.

4
  • "(..) how macro should work? Should they only process input data as symbols so they never have access to object before evaluation of lisp code?" - yes (IMHO) Commented Apr 25, 2019 at 21:12
  • @rsm how then I should go about and create functions at runtime? Commented Apr 25, 2019 at 21:15
  • (macro x) will do something with the symbol x before knowing what significance it has. Some implementations does macro expansion ahead of execution and doesn't have macros at all in runtime. These systems can be R5RS when eval was optional. The expansion should be possible to put in (macro x) place and it should work interchangeably. Commented Apr 25, 2019 at 23:54
  • 1
    If your macro needs a value at macroexpansion-time, then it needs to get that value from somewhere. There is no way around that. How the macro gets it, that can be via EVAL, asking a symbol for its value, retrieving it from some data structure, etc. All have in common: these values need to be retrievable at macroexpansion-time. Commented Apr 26, 2019 at 5:24

1 Answer 1

3

In Common Lisp: creating and compiling functions at runtime.

CL-USER 20 > (defparameter *input* '((foo . 10) (bar . 20)))
*INPUT*

CL-USER 21 > (defun make-my-functions (input)
               (loop for (symbol . number) in input
                     do (compile symbol `(lambda  () ,number))))
MAKE-MY-FUNCTIONS

CL-USER 22 > (make-my-functions *input*)
NIL

CL-USER 23 > (foo)
10

CL-USER 24 > (bar)
20

From a local variable:

CL-USER 25 > (let ((input '((foo2 . 102) (bar3 . 303))))
               (make-my-functions input))
NIL

CL-USER 26 > (bar3)
303

With a macro, more clumsy and limited:

CL-USER 37 > (defparameter *input* '((foo1 . 101) (bar2 . 202)))
*INPUT*

CL-USER 38 > (defmacro def-my-functions (input &optional getter)
               `(progn
                  ,@(loop for (symbol . number) in (if getter
                                                       (funcall getter input)
                                                       input)
                          collect `(defun ,symbol () ,number))))
DEF-MY-FUNCTIONS

CL-USER 39 > (def-my-functions *input* symbol-value)
BAR2

CL-USER 40 > (foo1)
101
Sign up to request clarification or add additional context in comments.

6 Comments

This works for simple case, but it seems that my simple case is not equal the complex one. In my original code I have list of names that I can get at runtime and object I call this on. Not sure but this is like passing CLOS object and list of generic functions and function or macro generate new normal function where generic is inside and it call on that CLOS object. And object can be in let.
@jcubic: maybe you should explain what you actually want to do. Just posting code in your own Lisp dialect is probably not of much help, when we don't know what it does or should do.
@jcubic: as I showed you in my example, Common Lisp can generate code and compile it - without macros - no matter what it calls and what the arguments are. Basic rule: if you want to do something at runtime, based on runtime data, use a function.
So what I need is to have something like merge of two it seems incompatible concepts closures and macro expantion or a way to have it. (let ((x <EXTERNAL OBLECT VALUE>) (name 'foo)) '(define (,name) x)) before define there is back tick . so what i need to have function name at runtime and value from closure. Maybe I need different define function that generete new function when used inside let. in scheme this don't work (at least in biwascheme) you need (define foo (let ((x 10)) (lambda () x))
@jcubic: in Scheme one would use a plain EVAL, instead of CL's COMPILE. Maybe a specific Scheme implementation has the equivalent to it.
|

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.