Last week @pez asked me if YS could be used to refactor his Calva CircleCI config.yml
https://github.com/BetterThanTomorrow/calva/blob/published/.circleci/config.yml
I just finished a PR for that with 30 iterative commits resulting in:
https://github.com/ingydotnet/calva/blob/dev/.circleci/config.ys
which evaluates to an equivalent config.yml file with:
$ make build
ys --load --yaml --ordered config.ys >> _config.yml
mv _config.yml config.yml
The README.md explains it pretty well:
https://github.com/ingydotnet/calva/blob/dev/.circleci/README.mdStarting a thread to link elsewhere.
That's awesome
This Calva was released with YamlScript. 💪 🚀
Three weeks ago, homoiconicity was just a gentlefolks' conceit. Now it is rising, reptilian, out of the drains.
I'm late to this party, but I agree wholeheartedly with @phill. Though I wonder... Do you think "code-as-data" might be a preferable expression to "homoiconic"? To my mind "code-as-data" is the important concept and would likely result in less debates.
@phill what are you alluding to exactly? Don't want to make assumptions.
I am impressed & thrilled but most of all honored to be present at this time in history.
Because there is some serious pedantry (and I mean that in the most positive sense) about homoiconicity.
I feel the same sense of being there when something really important is happening!
But there is nothing elitist about YAML.
And while (on one hand) Lisp macros owe a lot to homoiconicity, (on the other hand) the Everyman in programming and IT does not know why they should care about macros.
But now with YamlScript, basically a self-transforming data instance, the homoiconicity shoe is completely on the other foot.
The Everyman in IT will dabble happily in YamlScript, because it is homoiconic!
It was a bit poetic to describe it as "homoiconicity rising up, reptilian, out of the drains"; but my powers of expression were inadequate to convey the revolution that we're on the cusp of: the abstruse concept having been plucked from the ivory towers, and offered to the IT masses: who will shortly topple all ramparts to bring it to all corners of dull-and-boring configuration. A bottom-up crash introduction of functional expression from the very people the ivory tower considered least likely!
This is quite interesting I was thinking that you were saying clojure is homoiconic and the yamlscript is not. I thought about this topic quite a bit and I'm unsure whether YS is truly homoiconic and also whether a clojure is. Some differing opinions out there.
The opinions doesn’t matter so much, me thinks. 😃
This is a compilation, where =: forms transform into defs or lets.
I'm not sure if this breaks homoiconicity.
$ ys -ce '
x =: 123
defn foo(y):
z =: 321
=>: z / y
'
(def x 123)
(+++ (defn foo [y] (let [z 321] (/ z y))))
I guess you could think of it as an elaborate macro expansion.
This is the same compilation with each of the 7 stages exposed.
$ ys -ce '
x =: 123
defn foo(y):
z =: 321
=>: z / y
' -d
*** parse output ***
({:+ "+MAP", :! "yamlscript/v0/code"}
{:+ "=VAL", := "x ="}
{:+ "=VAL", := "123"}
{:+ "=VAL", := "defn foo(y)"}
{:+ "+MAP"}
{:+ "=VAL", := "z ="}
{:+ "=VAL", := "321"}
{:+ "=VAL", := "=>"}
{:+ "=VAL", := "z / y"}
{:+ "-MAP"}
{:+ "-MAP"}
{:+ "-DOC"})
*** compose output ***
{:! "yamlscript/v0/code",
:%
[{:= "x ="}
{:= "123"}
{:= "defn foo(y)"}
{:% [{:= "z ="} {:= "321"} {:= "=>"} {:= "z / y"}]}]}
*** resolve output ***
{:pairs
[{:def "x ="}
{:exp "123"}
{:defn "defn foo(y)"}
{:pairs [{:def "z ="} {:exp "321"} {:exp "=>"} {:exp "z / y"}]}]}
*** build output ***
{:pairs
[[{:Sym def} {:Sym x}]
{:Int 123}
[{:Sym defn} {:Sym foo} nil {:Vec [{:Sym y}]}]
{:pairs
[[{:Sym def} {:Sym z}]
{:Int 321}
{:Sym =>}
{:Lst [{:Sym /} {:Sym z} {:Sym y}]}]}]}
*** transform output ***
{:pairs
[[{:Sym def} {:Sym x}]
{:Int 123}
[{:Sym defn} {:Sym foo} nil {:Vec [{:Sym y}]}]
{:pairs
[[{:Sym def} {:Sym z}]
{:Int 321}
{:Sym =>}
{:Lst [{:Sym /} {:Sym z} {:Sym y}]}]}]}
*** construct output ***
{:Top
[{:Lst [{:Sym def} {:Sym x} {:Int 123}]}
{:Lst
[{:Sym +++}
{:Lst
[{:Sym defn}
{:Sym foo}
nil
{:Vec [{:Sym y}]}
{:Lst
[{:Sym let}
{:Vec [{:Sym z} {:Int 321}]}
{:Lst [{:Sym /} {:Sym z} {:Sym y}]}]}]}]}]}
*** print output ***
"(def x 123)(+++ (defn foo [y] (let [z 321] (/ z y))))"
(def x 123)
(+++ (defn foo [y] (let [z 321] (/ z y))))It's certainly all data transformations.
I'd like to have a solid story for yamlscript homoiconicity...
Am much too exuberant to split hairs. If YS is YAML & its data literals are YAML, then that just about does it for me, and if YS can generate data that also happens to be valid YS then that's 110%.
I think it's a topic that will be raised in the future. Glad to have your insights 🙂
YS is and must be valid YAML. I didn't even write the first stage (parser). That's the java yaml parser snakeyaml-engine. Writing a parser is a LOT of work 🙂
snakeyaml (or maybe snakeyaml-engine) backs clj-yaml
snakeyaml -> yaml 1.1 snakeyaml-engine -> 1.2
I will likely swap out that parser later as it has edge cases spec failures. but more than good enough for now.