Is there any way to define function args using macro?

30 views
Skip to first unread message

dmitriy.k...@gmail.com

unread,
Aug 13, 2018, 5:33:40 AM8/13/18
to Lisp Flavoured Erlang

Hello,

It's easy to use macros in "function body", but I'd like to generate function with pattern-matching args using macros. For example:

lfe> (defmacro empty-1st () '(('() _) 'yes))
empty-1st
lfe> (macroexpand '(empty-1st) $ENV)
(('() _) 'yes)
lfe> (defun is-1st-empty (empty-1st) ((_ _) 'no))
is-1st-empty
lfe> (is-1st-empty [] 'x)
exception error: #(undefined_func #(is-1st-empty 2))

But if I substitute macro with what it expanded to, function of arity 2 is created and works as expected:

lfe> (defun is-1st-empty (('() _) 'yes) ((_ _) 'no))
is-1st-empty
lfe> (is-1st-empty [] 'x)
yes
lfe> (is-1st-empty [1] 'x)
no

Is there any way to force LFE to expand macro first, and then to interpret outer form (defun) ?

Thanks.

Robert Virding

unread,
Aug 13, 2018, 7:11:54 AM8/13/18
to Lisp Flavoured Erlang
No, the macro expansion works from the outside in. The expansion of defun/define-function is purposely very restricted so it doesn't really modify the basic structure in the original form. That is why when the argument list at the top-level is a list of symbols it is not affected. Also when you give a list of clauses the structure of each clause is not changed so the whole argument list as one unit is not macro-expanded and you get the same number of arguments as is given for each clause. Same with the body and its guard as 'when' is a reserved word and will never be macroexpanded. You can however use macros for each argument which will be expanded and you can have the first form in the body expand to a '(when ...)' guard.

I refused to expand macros with the same name as core forms as it makes it too easy to really screw things up, especially for beginners. What happens if define cons as a macro? You are allowed to define the macro but it will never be used. Maybe I should generate an error in this case?

Robert

Dmitriy Kargapolov

unread,
Aug 13, 2018, 12:41:58 PM8/13/18
to Lisp Flavoured Erlang
Thank you Robert for clarifying the case I mentioned.

I tried to play with cond/case/when instead of defun and this also was not much successful. May be I do something wrong from CL perspective. But let me explain in general what is the purpose.

I always felt a lack of meta-programming in Erlang. For example I need to parse some protocol. And code should be efficient (as much as it can be in Erlang). Natural approach is to have multi-head function with patterns for any piece of API/Protocol input. This may be a tedious work. And when you have to match a lot of similar patterns with difference in details, meta-programming might help.

Initial idea was to implement a macros, when you write:
(some-parser-macro (1 'a) (2 'b) (3 'c))
and this would work like if you write:
(defun some-parser
  ((1) 'a)
  ((2) 'b)
  ((3) 'c))

Or even better, adding one more macro:
(defmacro some-pattern-to-result-mapping
  ((1) 'a)
  ((2) 'b)
  ((3) 'c))
and writing
(another-parser-macro (1 2 3))
to have it producing same matching function.

My examples are primitive, just to give an idea. Real matching patterns and actions are functions of many parameters and number of patterns will be roughly product of dimensions.

I understand that all this "magic" I can do following "data is program and vice versa" idiom, but I want it to happen at compile-time, not runtime.

At this point I don't see clear way how to implement it in LFE. Or in Common Lisp in general? I have heard many positive things about extremely powerful Lisp macros. Did I miss something?

Thank you.
Reply all
Reply to author
Forward
0 new messages