Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix macro require #273

Closed
agentultra opened this issue Aug 11, 2013 · 9 comments
Closed

fix macro require #273

agentultra opened this issue Aug 11, 2013 · 9 comments
Labels

Comments

@agentultra
Copy link
Member

Require'd macros cannot reference global namespace of their module

;; mac.hy
(defn foo [a]
  [a])

(defmacro bar [baz]
  (quasiquote
    (do (foo (unquote baz)))))

;; bang.hy
(require mac)

(bar "boop")

;; Results in:
;; NameError: global name 'foo' is not defined

Which is not terribly useful.

@olasd
Copy link
Member

olasd commented Aug 12, 2013

Well yeah, that's because your function is actually defined at runtime, that is, not in the context where the macro is defined.

Tried wrapping the defn in an eval-when-compile?

@olasd
Copy link
Member

olasd commented Aug 12, 2013

(after a quick test, that doesn't work either... ??)

@khinsen
Copy link
Member

khinsen commented Aug 19, 2013

What you need to add to bang.hy is (import [mac [foo]]).

Explanation: (require mac) makes the macros defined in mac.hy available in bang.hy at compile time (more precisely, hy-to-python compile time). It doesn't make foo available at run time. Wrapping the definition of foo in eval-when-compile would allow to call foo in the definition of the macro bar, but it doesn't magically import it into another module.

So far for how Hy works right now. The example shows a common Lisp idiom consisting of a macro expanding into an expression involving a call to a function defined in the same module. Hy should have some nice way to express this. This is less straightforward than in other Lisps due to the way symbols and namespaces work in Python.

Problem #1 is deciding how symbols used in macro expansions should be taken from by default. For now, they are taken from the namespace in which the macro is used, not the one in which the macro is defined. Worse, there isn't any way to specify that they should be taken from the macro-defining namespace. There should be one, and probably it should be the default. But doing this is not trivial.

The fundamental issue is that Python provides no way to refer to a symbol inside a given namespace directly. What a symbol means is always defined by the import statements of the module it appears in. We could make macro expansions include some imports, of course, but then we risk a name clash with explicit imports made in the module that uses the macro. One possible but ugly solution is to use gensyms to refer to such automatically imported names.

@agentultra
Copy link
Member Author

That's precisely the work around I've used to skirt the issue.

Don't really have a constructive solution yet. Not sure we can implicitly import * when using REQUIRE

Sent from my mobile

On Aug 19, 2013, at 8:53 AM, khinsen notifications@github.com wrote:

What you need to add to bang.hy is (import [mac [foo]]).

Explanation: (require mac) makes the macros defined in mac.hy available in bang.hy at compile time (more precisely, hy-to-python compile time). It doesn't make foo available at run time. Wrapping the definition of foo in eval-when-compile would allow to call foo in the definition of the macro bar, but it doesn't magically import it into another module.

So far for how Hy works right now. The example shows a common Lisp idiom consisting of a macro expanding into an expression involving a call to a function defined in the same module. Hy should have some nice way to express this. This is less straightforward than in other Lisps due to the way symbols and namespaces work in Python.

Problem #1 is deciding how symbols used in macro expansions should be taken from by default. For now, they are taken from the namespace in which the macro is used, not the one in which the macro is defined. Worse, there isn't any way to specify that they should be taken from the macro-defining namespace. There should be one, and probably it should be the default. But doing this is not trivial.

The fundamental issue is that Python provides no way to refer to a symbol inside a given namespace directly. What a symbol means is always defined by the import statements of the module it appears in. We could make macro expansions include some imports, of course, but then we risk a name clash with explicit imports made in the module that uses the macro. One possible but ugly solution is to use gensyms to refer to such automatically imported names.


Reply to this email directly or view it on GitHub.

@khinsen
Copy link
Member

khinsen commented Aug 20, 2013

There is one solution I thought of but I don't like it.

After the require, we know that the module has been loaded and is in memory. That means it's in sys.modules. So we could replace the symbol by an explicit lookup in the original module starting at sys.modules. That's ugly, and that's slow, but it should work.

And there's of course the gensym approach which is also ugly, but at least not slow.

@paultag
Copy link
Member

paultag commented Aug 22, 2013

gensym would be interesting to add, even if we have a better solution for this bug

@khinsen
Copy link
Member

khinsen commented Aug 22, 2013

I thought we already had gensym, but didn't check. It's pretty much compulsory for non-trivial macros (once you start caring about hygiene), so I'll create an issue for that immediately.

@paultag
Copy link
Member

paultag commented Aug 22, 2013

Aye, thank you!

@Kodiologist
Copy link
Member

Kodiologist commented Feb 26, 2017

I think the way macros and modules play together is now firmly established enough that we can say this isn't a bug. If you want the expansion of bar to be able to refer to a function foo defined in mac, you need to include (import [mac [foo]]) or something in that expansion. Otherwise, how could Hy tell that by foo you meant mac.foo instead of bang.foo?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants