spy16 / sabre

Sabre is highly customisable, embeddable LISP engine for Go. :computer:
GNU General Public License v3.0
28 stars 5 forks source link

Dynamic namespace similar to Clojure #5

Closed lthibault closed 4 years ago

lthibault commented 4 years ago

Hi @spy16 ,

I've been making strides on my lisp project, and I'd like to implement something similar to Clojure's ns special form (minus the Java interop stuff, obviously).

My intuition is that this kind of functionality falls outside of Sabre's scope (similar to https://github.com/spy16/sabre/issues/3).

If that's the case, I'm not sure how to go about implementing this. Any suggestions?

spy16 commented 4 years ago

I've been thinking about this too. Importing files is definitely needed. And that would require some isolation between imported things. May be some basic version of namespaces should be done in sabre itself.

One simple approach you can use is to implement scope interface and make sure everything passed to Bind call is done with ns/name format. You can even support automatic resolution of namespace. For example, if user enters only foo you resolve this to current-ns/foo in your Scope implementation. Same trick goes for imported files. Implement import function that uses filename or a ns header and binds all the values from the file with that namespace.

lthibault commented 4 years ago

May be some basic version of namespaces should be done in sabre itself.

Sure, that would be helpful, especially if the facilities provided by Sabre are minimal and unopinionated.

Specifically, I don't think Sabre should force any particular syntax upon the user. I'm deliberately trying to avoid Clojure's import-path syntax, which mixes various types of separators (e.g.: (clojure.core/refer-clojure)), and do something more like this: namespace.sub_namespace.some_function.

Maybe Sabre should just provide an example of your suggested implementation (e.g. in the REPL rather than the sabre namespace) ? It seems like a good first-step that doesn't close any doors.

lthibault commented 4 years ago

Ok, after thinking about this some more, I'm still stuck. This is very much a language design issue, but if you have any insights, I'd be most appreciative!

What you describe above solves the problem of encapsulating symbols within a namespace, and it makes perfect sense. I'm still stuck on the second piece of the puzzle, though: how can I implement the switching of the current namespace?

In Clojure, I can create a new namespace and set it as the current namespace (= *ns*) as follows:

user=> (ns my.new.namespace)
nil
my.new.namespace=>

Do you have any insights on how this might work in Sabre?

(I think this is where it might make sense for Sabre to provide some functionality ... maybe.)

spy16 commented 4 years ago

Check out the MapScope implementation in https://github.com/spy16/sabre/tree/namespaced-scope.. I did a simple implementation of Clojure like Namespaces (Has ns to switch namespace, has *ns* that resolves to current namespace name). This does not support sub-namespaces and it is more like Go packages. Let me know your thoughts.

I have also used / as namespace separator because, i do want to add support for method invocation and . is more conventional approach for that.

Note: I haven't merged this to master and haven't decided wether I should merge or not as well. Like you said, not yet sure if this should exist as part of sabre package itself or not.

lthibault commented 4 years ago

Closing this as it's largely addressed by the example in branch slang.