Comments (12)
However [].bar is hard because there is no [] symbol anywhere in the namespace.
Not quite. Issue is that the moment reader sees [
it drops into the logic that parses a vector and stays there until it reaches a matching ]
and when it does, it's considered end of one form. Following .
will not be considered as part of this. Instead another symbol .Cons
will be emitted . Instead of having a form that expresses [].Cons
you'll end up with 2 forms a list []
and a symbol .Cons
..
But I think it's best not to worry about this now at all. Gain in simplicity is bigger compared the loss in this minor detail.
from sabre.
And i think it would be nicer to allow kebab case naming for member access.
I am considering may be both foo.GetTheName andd foo.get-the-name should work. Let me know what you think..
I'm very much in favor of this. Kebab-case is certainly convenient, but forcing case-conversion adds cognitive overhead for users, and may at times be more confusing than the native names.
Also, I am thinking no dots allowed in symbols similar to all other languages.
Strongly agree. Dots have special meaning. Disallowing their use in symbols helps signal intent. Furthermore, we should avoid letting people abuse dots in weird ways in case we need to make changes to field lookup semantics in the future.
Overall:
from sabre.
I've been thinking of this on my end as well, and agree that such functionality should be exposed.
I saw it as a (.method-or-field target)
form, however, implemented by a ReaderMacro
. I'm not opposed to the .
function approach, but I'm curious why you prefer it?
In my mind, a Go-flavored lisp should aspire to the same minimalism that one finds in Go. One minor annoyance I have with various lisps (including Clojure) is the sheer number of exported symbols in the default namespace. Clojure's core
namespace has over 200 exported functions, for instance!
One of my aspirations for my own project is to keep the language spec very small. In so doing, I hope to attain the same kind of simplicity as one finds in Go, and in order to achieve this, I would argue that we should build a lisp engine that reduces the number of functions that need to be implemented, rather than pushing functionality out to functions. A powerful introspection system for native Go structures seems like an opportunity to do just that.
I'm not sure what else we could be doing to move in this direction, but I'm interested in any thoughts you might have.
Returning to the point at hand, my gut tells me this should not be a function, but I'm open to being wrong!
Addendum: regarding the point about Go-style simplicity above, I think this also touches upon an important marketing consideration for Slang. If we want this library to take off, it's important that we differentiate it from all the other "make a lisp" libraries on GitHub. A heavy emphasis on making simple (i.e.: small, feature-conservative) lisps is a very interesting niche in this respect. We would benefit from being unique as well as being aligned with the philosophy of the host language (Go).
from sabre.
I have with various lisps (including Clojure) is the sheer number of exported symbols in the default namespace
Same here. That's why i took this decision in fact. My idea was that a minimal scope would export only few selected functions like .
, def
, fn*
etc. and things like cons
, conj
, seq?
etc. would be built using pure lisp and are not included by default.
I'm not opposed to the . function approach, but I'm curious why you prefer it?
To be honest, I am not totally happy with it either, i am definitely open for suggestions. Only reason I picked this was to ensure there is no special handling of things. For example if I picked (.member target)
approach, everytime a list is evaluated, the evaluation logic would have to check if the first item in the list starts with a .
..
It's not possible to do this with a ReaderMacro
in a generic way as it stands, and here's why: ReaderMacro
is completely decoupled from a Scope
, so it has no knowledge of what target values are available. Even if we introduce a new member access
expression/form that reader emits, we will also have to provide a way to construct this expr without reader (lisp principle: code and data are not different)..
I can think of following alternatives here:
- Make
Reader
depend on aScope
and make it emit the member being accessed as the value from the reader. - Enable
(target.member args...)
kind of access which would make it simpler (but need to handle ambiguity when a symbol itself has a.
in it. - Enable
((.member target) args...)
approach
I think approach 2 would be the simplest to use in most cases.. But the problem is, we will not be able to use it against inlined values.. i.e., ((.Cons []) 1)
can be done with approach 3 for example, but in approach 1 & 2 it would be ([].Cons 1)
which is ambiguous for parsing..
A powerful introspection system for native Go structures seems like an opportunity to do just that.
This is what i was going for too.
I was thinking of simplicity in terms of design of Sabre as library itself: Provide a bare-bones environment which can be built upon.
from sabre.
Enable target.member kind of access which would make it simpler, but we will lose capability to have nested namespaces like sabre.core.math (which i think is not necessary, let me know what you think)...
An alternative would be to take Python's approach and model namespace lookups as regular object lookups. Imagine you have a namespace with a foo.bar
symbol that maps to a type t struct { Baz int }
. The expression foo.bar.Baz
could be supported by the following algorithm:
- Look for a common substring in the namespace. We find that the namespace contains
foo.bar
- Get the corresponding object from the namespace. Call it
o
. - Trim the common substring
foo.bar
off of the fully-qualified lookup symbol,foo.bar.Baz
. The result isBaz
. - Repeat steps 1-3 using
o
instead of the namespace, until the the algorithm terminates.
Honestly, I really like this approach:
- It removes the need to support two distinct separators (
/
and.
) in order to resolve symbols. - It makes for a natural hierarchical grouping of symbols.
- It makes lookup conventions identical for namespaces and regular objects, reducing cognitive overhead.
This is one of the things I think Python does extremely well. This kind of encapsulation is (IMHO) the only real upside to modeling data as objects. Provided we don't encourage stateful objects, I see no downsides.
This is what i am going for too. In fact now that member access is allowed, i was considering to implement things like cons, conj etc. through this.
+1 for this.
I was thinking of simplicity in terms of design of Sabre as library itself: Provide a bare-bones environment which can be built upon.
Yes, I think this is also very important. My suggestion was more of a supplement than an alternative. Point is: I'm favor of strategically adding a little bit of complexity in a select few places in order to encourage the design of simple languages.
from sabre.
Enable (target.member args...) kind of access which would make it simpler (but need to handle ambiguity when a symbol itself has a . in it.
Actually, forgot to correct this part. This can be handled like you said and i really like this too.. It's how Go does it pkg.Symbol.Member.SubMember
etc. it's how Python does it.. But one problem i see is w.r.t., member access on literal values.. for example, to access Cons
method of a vector/list literals.. Like ([].Cons 1)
which would be hard to parse.. This is not a major problem though if we think it's okay to add some additional boilerplate in case of literals.. i.e., (let [empty-vec []] (empty-vec.Cons 1))
..
What do you think ?
from sabre.
This can be handled like you said and i really like this too..
Awesome - then consider me onboard
But one problem i see is w.r.t., member access on literal values..
Just to make sure I understand, the difficulty is exclusively at the parsing level because it involves some form of lookback / context? For example, foo.bar
is easy to parse because foo
can be located in the namespace. However [].bar
is hard because there is no []
symbol anywhere in the namespace.
Assuming I've understood the issue, I'm 100% onboard with your proposed mitigation strategy (which is basically to not worry it for now). It would nevertheless be good to handle this more elegantly in the mid-to-long term. Perhaps we can open an issue and get back to it later?
from sabre.
Ah yes, of course! Ok, makes sense.
But I think it's best not to worry about this now at all. Gain in simplicity is bigger compared the loss in this minor detail.
Totally agree.
from sabre.
Cool. I'll try to get this done when I get sometime. Thanks for bringing this up.. I got caught up in doing things similar to Clojure I guess..
from sabre.
Thanks for bringing this up.. I got caught up in doing things similar to Clojure I guess..
😅
No sweat - I'm happy to be part of the design process :)
from sabre.
Just to put the above discussion into final points:
- No special treatment for namespaces. They are just objects bound in the scope.
- Simply split the fully qualified symbol using
.
as the delimiter and do recursive lookups until termination.
And i think it would be nicer to allow kebab case naming for member access. (i.e., if the method of a type Foo
in Go is named GetTheName
, from Sabre it would be better to have foo.get-the-name
kind of access)... I am considering may be both foo.GetTheName
andd foo.get-the-name
should work. Let me know what you think..
Also, I am thinking no dots allowed in symbols similar to all other languages. Clojure allows this but in a weird & useless way: (def hello.world 10)
works and creates a binding, but when you try to use the symbol hello.world
somewhere it just throws ClassNotFoundException
.. I can't really think of a use-case where using .
in names can make it better/readable. But allowing it can be confusing (For example when i type foo.bar.baz
, it's not really clear if it is resolving baz
of foo.bar
or is foo.bar.baz
itself is a value?)..
from sabre.
This has been implemented. I have not done support for kebab case yet. For now going to keep only native names.
from sabre.
Related Issues (17)
- Support for metadata on symbols and collections
- Moving Slang to separate repository HOT 2
- Support goroutine invocation HOT 4
- Refactor Value interface HOT 2
- Macro expansion mutates original list
- FYI: Clojure implemented in Go
- Support for macros & special forms HOT 4
- how to implement comments HOT 6
- golang package and test best practice HOT 8
- export more internal functions from specials.go HOT 11
- Sabre Experience Report HOT 11
- Invoke on List type
- Migrate parens standard library to sabre HOT 3
- Archive Sabre HOT 1
- Cannot build with GO111MODULE=1 HOT 8
- Dynamic namespace similar to Clojure HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sabre.