Last active
August 29, 2015 14:02
-
-
Save orthecreedence/2e7d974cfbbed733347f to your computer and use it in GitHub Desktop.
Non-recursive macrolet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defpackage :mlet-nonr | |
(:use :cl)) | |
(in-package :mlet-nonr) | |
(defun %attack (item fn) | |
(format t "attacking ~a, then calling fn~%" (car item)) | |
(funcall fn (car item))) | |
(defmacro attack (item fn) | |
"This is a macro so we can bind to multiple values. In this case, %attack only | |
uses the first value, but this is just for brevity. Attack *must* be a macro | |
for my purposes." | |
`(let ((vals (multiple-value-list ,item))) | |
(%attack vals ,fn))) | |
(defmacro wrap (&body body &environment env) | |
"Wraps both the `item` and `fn` of any `attack` statement in the body with a | |
1+. The purpose is to show that we can use a macrolet to replace the meaning | |
of another macro additively without devlving into infinite recursion. | |
We do this by grabbing the `attack` macro function directly using the env | |
from one level up." | |
`(macrolet ((attack (item fn &environment ml-env) | |
(funcall (macro-function 'attack ,env) | |
`(attack | |
(1+ ,item) | |
(lambda (w) | |
(1+ (funcall ,fn w)))) | |
ml-env))) | |
,@body)) | |
;; this is the main call demonstrating the functionality. its desired | |
;; output: | |
;; | |
;; attacking 4, then calling fn | |
;; attacked. | |
;; => 6 | |
(wrap | |
(wrap | |
(attack 2 (lambda (x) (format t "attacked.~%") x)))) | |
;; the above should expand to: | |
(let ((vals (multiple-value-list (1+ (1+ 2))))) | |
(%attack vals | |
(lambda (w) | |
(1+ (funcall | |
(lambda (w) | |
(1+ | |
(funcall | |
(lambda (x) (format t "attacked.~%") x) | |
w))) | |
w))))) |
Note...the fix was to quote env
:
(funcall (macro-function 'attack ,env)
becomes:
(funcall (macro-function 'attack ',env)
Thanks, Bike/pjb on #lisp =]
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note that this works great in just about every impl I've tested except ECL, which is my target currently.
It fails with: