Git Product home page Git Product logo

Comments (16)

honix avatar honix commented on May 17, 2024

Can you please explain dot operator (?) here:
https://github.com/janet-lang/janet/blob/master/examples/life.janet#L19
And here:
https://github.com/janet-lang/janet/blob/master/examples/life.janet#L27

from janet.

bakpakin avatar bakpakin commented on May 17, 2024

The dot operator is like an array indexing operator. An expression a.b is treated by the compiler much like (get a b). The colon operator works with keywords. An expression a:b is treated by the compiler like (get a :b).

In some older version of janet, the dot operator was able to index with integer keys. In other words, you could do a.0 to get the first element of a tuple. I have removed that for now because I did not want to commit to the syntax, but I think it might be useful.

from janet.

bakpakin avatar bakpakin commented on May 17, 2024

The old behavior was removed as I was making some large changes to Janet internals about representation of integers. I have added it back with the latest commit 29ec30c. You should now be able to do things like

(var a @{})
(set a.0 :hi)
(print a.0) # prints :hi

from janet.

honix avatar honix commented on May 17, 2024

Hm.. Can we just disallow numeric keywords like :14 and then fetch indexes with same syntax.

a:14 => get item with index 14 from a (or key 14 if a is a dict)
a:cat => get item with key :cat from dict a
a:"baa" => get item with key "baa" from dict a

Think indexed container is a dict with integer keys only.

Update: Oh! Symbols can be used as keys. a:cat will fetch value with symbol-key cat.

Syntax example using "folder" notation:

a/14 => get item with index 14 from a (or key 14 if a is a dict)
a/cat => get item with symbol-key cat from dict a
a/:cat => get item with key :cat from dict a
a/"baa" => get item with key "baa" from dict a

Modules can be done in same fashion. As they already using this syntax.

from janet.

bakpakin avatar bakpakin commented on May 17, 2024

I'll have to think about this some more. I agree that the current syntax is not general enough, but I also don't want to complicate the parser too much, nor incur a table lookup at runtime for using module functions.

I like the current way of handling modules by just merging the symbols from the loaded module into the current environment because it allows really flexible imports like (import mymodule :prefix ""), which is like clojure's use (I realize this isn't well documented yet).

Right now, these shorthand syntax's are done in the compiler on a single symbol. This means that to the parser, all of these notations are just one symbol.

(type 'a:b) => :symbol
(type 'hello.1) => :symbol

I think that this functionality should be in the parser, and the compiler doesn't need to know anything about the syntax. The set special form will still need to know how to act like a put, however. After
the parser creates a tuple, the runtime would need to treat data structures as functions that look up keys.

Some ideas:

a:b => (a b) or (a :b) or maybe (get a b)
a.b.c.d => (a b c d) or maoybe (get a b c d)
a.b.c.1.2 => (a b c 1 2) or (a b c 1.2)?
a/"hello"/1.2e4/0x45 => (a "hello" 1.2e4 0x45)
a|b|"c"|:d => (a b "c" :d)

All of these have issues. Using a colon means keyword keys become different. A period is a valid
character in a number, so one could not have fractional numbers in such a form. The forward slash / is currently the division function. The pipe | wouldn't have any collisions, but it looks a bit strange.

All together I think it would take several changes to get this to work as smoothly as possible. I think the steps would be

  1. Allow calling data structures as functions.
  2. Update parser to support some infix tuple syntax
  3. Update set special form to take a tuple returned by the parser as an lvalue.

This also has the benefit that each of these three steps is a useful feature on its own.

from janet.

honix avatar honix commented on May 17, 2024

Agree!

But it needs to be made in simple but powerful form. This is Lisp! :)

My thoughts on some nested dict:

(((dict-1 key-a) key-b) key-c)

can be shorten

(@ dict-1 key-a key-b key-c)

No extra syntax involved.

from janet.

bakpakin avatar bakpakin commented on May 17, 2024

But it needs to be made in simple but powerful form. This is Lisp! :)

You're right, maybe simpler is better.

I have also been thinking about your "folder" notation, and I quite like it, regardless of whatever character becomes the delimiter. It would also make nested gets really easy as well.

a/b => (a b)
a/b/c => ((a b) c)

from janet.

bakpakin avatar bakpakin commented on May 17, 2024

The latest commit now has working symbols, keywords, and data structures as functions.

(:a {:a 1}) # 1
({:a 1} :a) # Also 1

I have been working on a lot of changes internal to the interpreter to simplify things a bit and deleting many lines of code. The external API should not have changed but be warned.

Also I have had a thought about how the set special could change. Perhaps the set special could take an lvalue that looks like the form that will retrieve the value like setf in other lisps, and remove the current shorthand. An example:

(def tab @{})
(set (tab :a) 1)

from janet.

honix avatar honix commented on May 17, 2024

Yay! Interesting, bi-directional logic here.

As I understand nested access will look like this:

((( {:a {:b {:c 1}}} :a) :b) :c)  # 1

And can be simplified by macro.

Love your choice towards simplicity.

from janet.

honix avatar honix commented on May 17, 2024

Yes, set form will work using same (getter) syntax.

from janet.

honix avatar honix commented on May 17, 2024

Seems number and string types can be added to funclike too:

# arg access (all ok!)
janet:675:> ({'a 1 'b 2} 'b)
2
janet:692:> ({:a 1 :b 2} :b)
2
janet:709:> ({"a" 1 "b" 2} "b")
2
janet:729:> ('(1 2) 1)
2

# call access (number and string fails)
janet:740:> ('b {'a 1 'b 2})
2
janet:757:> (:b {:a 1 :b 2})
2
janet:774:> ("b" {"a" 1 "b" 2})
error in repl: attempted to call "b", expected function|cfunction
  (fiber)
    in _thunk [repl] at (775:793) (tailcall)
janet:794:> (1 '(1 2))
error in repl: attempted to call 1, expected function|cfunction
  (fiber)
    in _thunk [repl] at (795:804) (tailcall)

from janet.

honix avatar honix commented on May 17, 2024

I think, basically, this condition can be removed, janet_get will error back:

janet/src/core/vm.c

Lines 226 to 229 in 6f3bc3d

if (!janet_checktypes(callee, JANET_TFLAG_FUNCLIKE)) {
janet_panicf("attempted to call %v, expected %T", callee,
JANET_TFLAG_CALLABLE);
}

Then there is no need for funclike. Or it is better to set funclike = indexed | dictionary. As they are actually callables here.
if (janet_checktypes(callee, JANET_TFLAG_INDEXED | JANET_TFLAG_DICTIONARY)) {

from janet.

bakpakin avatar bakpakin commented on May 17, 2024

My thought was that not everything should be callable as a function as it might hide errors, but playing
around with it it seems that there is no issue. In fact it seems being able to call nil is useful in certain cases, like in looking values up in a map.

Updated in 2a79d2e.

from janet.

honix avatar honix commented on May 17, 2024

There is an idea to interpret "call" access as a call:

janet:24:> (def obj {:wof (fn () (print "wof-wof"))})
{:wof <function 0x00574D80>}

# call access
janet:63:> (:wof obj)
wof-wof
nil

# arg access
janet:74:> (obj :wof)
<function 0x00574D80>

Pretty useful hack, but little complicated. What do you think?

from janet.

bakpakin avatar bakpakin commented on May 17, 2024

Its an interesting idea. When combined with table prototypes one could implement a very effective yet lispy OO paradigm with prototypical inheritance. Perhaps the function could receive obj as the first argument.

# Create a 'class'
(def Car @{:honk (fn [self] (print "I am a " (self :maker)))})

# Create an 'instance'
(def mycar (table/setproto @{:maker "Subaru"} Car))

# Make a 'method call'
(:honk mycar)

I think an implementation could be made relatively simple and be efficient as well, which is a plus.

I had been playing around various ways of implementing OO before non-function types were callable,
and this seems better.

Edit: This should be a separate issue though

from janet.

honix avatar honix commented on May 17, 2024

Yep! Closing.

from janet.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.