janet-lang / janet

A dynamic language and bytecode vm
https://janet-lang.org
MIT License
3.45k stars 223 forks source link

allow `splice` to operate on dictionaries #1198

Closed CosmicToast closed 1 year ago

CosmicToast commented 1 year ago

Currently, the easiest way to confirm between a destructured and a &named call style is by manually rebinding all of the symbols. This is obviously a good idea if sanitization or some restrictions/overrides are desired, but there's certainly a better approach. However, there can be more convenient ways to do this.

The concept is to make (splice {:a :b :c :d}) be equivalent to :a :b :c :d. Code-wise, it's equivalent to treating dictionary arguments to splice as an array/concat reduction. I.e (splice {:a :b :c :d}) is exactly equivalent to (splice (reduce array/concat @[] (pairs {:a :b :c :d}))). Latter being significantly longer.

This is useful for converting from a destructured call to a &named call, which is useful when wrapping existing "user-friendly" functions. Conversions the other way around are challenging. In Clojure, destructured keyword style arguments take an :as, but this is already not the case in Janet. However, at least the above can be done as-is.

This also opens up interesting possibilities towards replacing the above snipper in general with [;kvs]. pairs could also be expressed in terms of (defn pairs [ds] (partition 2 [;ds])) which I personally find funny.

sogaiu commented 1 year ago

May be it doesn't matter but the order of the things that get spliced from the content of the dictionary is not really predictable [1] in the general case, right?


[1] The order of a key and its associated value needs to be preserved I presume.

CosmicToast commented 1 year ago

I would say so, yes. It can be cool to have ordered maps for funny use-cases like constructing lexers (see moo.js for instance), but we have PEGs so that's even better. Besides cases like this the order shouldn't generally matter.

primo-ppcg commented 1 year ago

(splice (reduce array/concat @[] (pairs {:a :b :c :d})))

Is this any different than ;(kvs {:a :b :c :d})?

Between

;(kvs {:a :b :c :d})
;(keys {:a :b :c :d})
;(values {:a :b :c :d})

I think all use cases are covered.

Splice is translated into a pusha in the vm, which itself is implemented in terms of janet_indexed_view. I think it would probably be necessary to add a new vm command in order to accomplish this (pusht or similar).

CosmicToast commented 1 year ago

Indeed, I always forget about kvs, so I guess that works.