yamlscript

Ingy döt Net 2024-08-13T15:51:58.913919Z

Hey everyone. I know I've been quiet here for the last week or so, but its just because I've been heads down on YS dev for the Exercism launch...

Ingy döt Net 2024-08-13T15:59:40.727089Z

Anyone who has seen one of my YS talks might remember that the https://github.com/kanaka/mal project was a major catalyst in the inception of YS. See https://github.com/kanaka/mal/pull/626 🙂 That PR never got any feedback until last week when the mal creator @clojurians115 reached to say he was back back from a hiatus. I asked him to contact me and today he did here! So I'd like you all to welcome him to #yamlscript 🌻

🎉 1
Ingy döt Net 2024-08-13T16:02:07.183979Z

I wanted to ask Joel and all of you a (fairly rhetorical (at least to me)) question: > Is YAMLScript a Lisp?

Ingy döt Net 2024-08-13T16:16:33.179299Z

What makes a Lisp? YS transpiles to Clojure and Clojure is a Lisp. Is it the syntax, the AST or something else? The transpilation of ys to clj is a 7 stage process as seen here https://gist.github.com/ingydotnet/8aacb48e83d9cd9929aabc22dd3e92ea There are 2 important AST states: • https://gist.github.com/ingydotnet/8aacb48e83d9cd9929aabc22dd3e92ea#file-tmp-xh53rwp0up-L22-L28 is clojure parts still in the original yaml input structure • https://gist.github.com/ingydotnet/8aacb48e83d9cd9929aabc22dd3e92ea#file-tmp-xh53rwp0up-L42-L52 is a full clojure AST ready to Print

Markus Agwin 2024-08-13T16:30:34.606179Z

My answer to "Is YS a Lisp" is a resounding NO. As can be read in https://en.wikipedia.org/wiki/Lisp_(programming_language), Lisp notation is either M-expressions car[cons[A,B]], like used in Mathematica, or indeed S-expressions. YS uses YeS expressions, which is not Lisp, but nevertheless retains the "Code is Data" paradigm.

Ingy döt Net 2024-08-13T16:33:17.866319Z

it can use ysexprs and other sugar forms that translate directly to sexprs. Certainly there are other Lisps that do similar?? You can also code YS in all sexprs...

Ingy döt Net 2024-08-13T16:34:24.704039Z

@markus.agwin not refuting you just growing the convo

Ingy döt Net 2024-08-13T16:35:05.837729Z

My answer is currently resounding MAYBE???

🤔 1
Joel Martin 2024-08-13T19:15:19.175969Z

Well, I didn't realize I would be pulled into a religious war 🤣. I don't think I can give a definitive answer to this. However, I can provide some thoughts from my experience of personally implementing mal in a few dozen languages. I think there are two aspects that make a language Lisp-like: syntax and internal operation/mechanisms. The syntax level and questions of homoiconicity are actually the harder level to answer for this question. I've had many discussions over the years with colleagues (including early Clojure contributors) about what exactly that term means and everybody has a different opinion. One aspect of homoiconic languages is that you should be able to round trip from source code to AST and back to source code. Almost no popular/modern Lisp complete fulfills this requirement due to macros. Reader macros in particular mean that you can't get back from the AST to source code. But even regular macros break this ability. You could in theory track macro information in metadata or something to be able to get back to the original but I don't know of any language that does that. fexprs are one way of getting the power of macros in a more homoiconic way. If YS is thought of as a set of complex macro transformations from the original source to the "true" source form, then you could argue that YS has a form of homoiconicity I suppose. As far as I can tell, YS doesn't have a full built-in macro system yet right? I think full AST macros and a native eval meta-circular evaluator (function that can evalulate YS code directly) is probably important for YS to make claim to a Lisp heritage. The ability of macros to dynamically generate and evaluate an AST during program read/compile/eval is definitely less easy to use if the AST differs a lot from the default syntactical representation, however. I've even heard it argued that Clojure's hash-map literals mean that the language is not fully round-tripable and therefore it is not 100% homoiconic because key order is not maintained. That's the sort of bike-shedding that happens when you try and nail down something like homoiconicity. The second aspect of internal operation/mechanism seems like it would be even harder to answer. But over the years I've come up with a good rule of thumb: how easy and concise is it to implement a mal interpreter in that language. What I've found in practice is that the more "Lispy" the internals of a language are, the easier it is to implement mal using that language (the language syntax is much less important when it comes to this). And likewise, creating a mal implementation of mal in a language will expose which parts of the language are Lisp-like and which are not. To make it concrete, Ruby is a very Lisp-like language. It very much feels like Ruby is a Lisp language with a object-oriented skin around it. For example, compare the core library of mal implemented in https://github.com/kanaka/mal/blob/master/impls/ruby/core.rb as opposed to https://github.com/kanaka/mal/blob/master/impls/java/src/main/java/mal/core.java . I haven't done an implementation of mal using YS (nor used YS in anger at all TBH), so I can't really say how Lisp-like YS feels. From poking around in the code and docs my guess is that the internals/operation are probably quite Lisp-like, especially given it's inspiration in mal and the fact that it compiles to Clojure/SCI. Whew, that became a bit long-winded. I probably should have broken up that more but that's what comes to mind. Was that type of non-commital answer what you were looking for 😄.

Ingy döt Net 2024-08-13T19:31:05.388829Z

@clojurians115 that was a gorgeous response and I appreciate you taking time to do it. No war at all. I've only stated that YS might be a Lisp and might be homoiconic. Really I just wanted to start some fun conversation. No other agenda for this. @phill brought up homoiconicity here in April: https://clojurians.slack.com/archives/C05HQFMTURF/p1713486686334549?thread_ts=1713474866.964849&cid=C05HQFMTURF and @danielmgerson was interested when I visited him in London in May https://clojurians.slack.com/archives/C05HQFMTURF/p1717843326903329 I have more to respond to but will use separate msgs...

Joel Martin 2024-08-13T19:35:29.055319Z

Yeah, I haven't read back in the channel, but I'm sure my elaboration above was probably repeating a lot of points already made here.

Joel Martin 2024-08-13T19:38:47.696099Z

In the end, I think you'll need to finish your mal implementation in yamlscript and then you can tell us all how "Lispy" it is 😉. BTW, on the code-as-data front, it does strike me that there might be an opportunity for an alternate syntax of YS that is closer to sexprs. I.e. something that translates more directly to the intermediate "build" form of the AST. Not saying you should do that, but it might be interesting to explore.

Ingy döt Net 2024-08-13T20:02:13.095439Z

More about that in https://clojurians.slack.com/archives/C05HQFMTURF/p1723577426565109 Definitely going to do the YS/MAL PR sooner than later. I'll just port my Perl (a very Lisp language that was the main inspiration for Ruby!). I suspect I could get the PR done in a few hours. ^^ Total Hacker Hubris 😕

Ingy döt Net 2024-08-13T20:07:13.702319Z

> I think there are two aspects that make a language Lisp-like: syntax and internal operation/mechanisms. Totally agree. YS has a Lispy model, but usually not a Lispy syntax. Roundtripping source->ast->source isn't a thing yet, but is on my radar. I'd have to pick a canonical style for various forms, where a Lisp barely needs to. But that's not uncommon in languages like Go where where canonical code style is nearly enforced... When I get around to a full nrepl story I'll likely need to take this on...

Ingy döt Net 2024-08-13T20:09:59.079159Z

exactly that term means and everybody has a different opinionSame perception. I was (pleasantly) surprised when @phill was saying (essentially) that YS was "homoiconic where it mattered"

💯 1
Ingy döt Net 2024-08-13T20:20:17.206989Z

> Ruby is a very Lisp-like language. I was in (Perl inventor) Larry Wall's kitchen talking with him and his wife Gloria when it came over the radio that John McCarthy had passed away. Larry told a funny story about a very early Perl presentation where he described Lisp as having all the visual appeal of oatmeal with fingernail clippings on mixed in. Unbeknownst McCarthy was in attendance and nonplussed, but Larry said "I only meant Visual appeal; otherwise Perl was completely inspired by Lisp. Of course these days Perl is usually compared to a dumpster fire 😂 From the Ruby wikipedia page: > According to the creator, Ruby was influenced by https://en.wikipedia.org/wiki/Perl, https://en.wikipedia.org/wiki/Smalltalk, https://en.wikipedia.org/wiki/Eiffel_(programming_language), https://en.wikipedia.org/wiki/Ada_(programming_language), https://en.wikipedia.org/wiki/BASIC, https://en.wikipedia.org/wiki/Java_(programming_language), and https://en.wikipedia.org/wiki/Lisp_(programming_language).

Joel Martin 2024-08-13T20:24:04.271859Z

That's a great anecdote. I've never met Larry Wall but from what I know he seems like an very interesting person.

❤️ 1
Joel Martin 2024-08-13T20:25:12.937049Z

Likewise McCarthy, although a very different personality I would guess.

Joel Martin 2024-08-13T20:26:58.636979Z

My father is also a linguist by trade so Larry's writings had a deep resonance for me. I was a perl enthusiast early on. Less so after learning python and then later Clojure. A lot of the perl philosophies have come to be seen as anti-patterns.

Ingy döt Net 2024-08-13T20:35:10.412579Z

> As far as I can tell, YS doesn't have a full built-in macro system yet right? Not yet. It has internally hard coded macro-like functions that happen mostly at the 6th (transform) stage of compilation. There have long be plans to introduce a user facing defys system for writing YS functions that alter the AST(s) during compilation. One main thing preventing this atm is deciding the AST is stable. Can't ask people to change their defys s every time we change the AST. Way less to worry about in a Lisp! > If YS is thought of as a set of complex macro transformations from the original source to the "true" source form, then you could argue that YS has a form of homoiconicity I suppose. Interesting. YS is a fancy YAML "loader" which the spec defines in stages. It loads YS in all the normal ways a spec compliant loader is encouraged to, but adds a couple stages. Then sprinkled in are some tweaks to make it DWIM. The idea is that eventually we have a stable AST (or maybe an AST API abstraction) and then all the special tweaks are pulled out and reapplied as defys macros. This means of course that users can change a lot of how YS looks just like I'm doing now. And in a lexical (probably file based) scope. Execution/compilation order also has difficulties to solve. I think ClojureScript's macros had similar hurtles. YS being Clojure can still define Clojure defmacro macros, but of course that's not what we're talking about with defys.

Ingy döt Net 2024-08-13T20:38:07.123339Z

> My father is also a linguist by trade so Larry's writings I recall realizing well after uni that I probably should have doubled majored in Linguistics 😄 Full respect to those that have. Larry was always more into linguistics than programming languages, I've observed. Gloria is also a linguist. They met in Uni!

👀 1
Ingy döt Net 2024-08-13T16:03:15.088259Z

A separate question and one we've talked about some before: > Is YAMLScript homoiconic?

Daniel Gerson 2024-08-15T14:27:11.248279Z

Agree with Markus's sentiment. I also don't want to get stuck in definitions. If you use YAMLScript as a macro language for YAMLScript and it has first class REPL support, then I'd say yes it is. Or rather that's the interesting part of homoiconicity that I care about...

Markus Agwin 2024-08-15T15:36:22.414679Z

The heck. Even Einstein developed his General Relativity under a guiding Principle. Turns out this "Mach Principle" had come in many formulations, all blurred, and in the end some solutions of GR obeyed some of the Mach-versions, in some situations not at all. Einstein kept insisting on the Principle, calling solutions not obeying as "non physical". In that sense homoiconicity is an example of the guiding principle no creator can do without.

Ingy döt Net 2024-08-15T15:39:50.901129Z

> first class REPL support @danielmgerson when I think we've accomplished that, I'm going to ask you to confirm

Ingy döt Net 2024-08-13T16:07:03.344539Z

I suspect @danielmgerson and @phill will have things to say here. 🙂

Markus Agwin 2024-08-13T17:26:58.860449Z

This is a tough one. I rewatched the https://www.youtube.com/watch?v=o7zyGMcav3c&t=1335s on the subject. Hmmm. I would give the "it depends" answer. I'd say, tentatively, we will see in its use whether YAMLScript is homoiconic. I think any language that is alive is defined in a large part via it's use. If people are going to write Macros for ys in Clojure, I'd say: "homoiconic? rather not". Moreover, I'd like to make the distinction between 1) libYamlScript and 2) YS-Cli. with 1) libYamlScript, YS is used to generate JSON-structures, so the data resulting out of the code is never homoiconic. All the more so, the reason that ys is used within, say, Python, makes the whole discussion about homoiconicity ridiculous. with 2) YamlScript CLI, one can do ys --load --yaml so the produced data can be made homoiconic. All in all, I am not sure whether it is really necessary to clarify this point. Better settle it case by case referring to the concrete problem that is solved using YAMLScript.

👍 1
Ingy döt Net 2024-08-13T16:27:13.203669Z

In other news I'm about to spend the next few hours pair programming with the author of https://github.com/biojppm/rapidyaml (the world's fastest YAML C++ parser) to have it replace SnakeYAML as the parser stage of the YS compiler... We've already spent a too much time fighting JNA + Graal trying to get it working. We're close... Wish me luck!

🍀 3
Joel Martin 2024-08-13T19:30:26.565109Z

@ingy You might already be aware of this, but I have another project called https://github.com/kanaka/miniMAL. It's a Lisp language that uses JSON source code. I call it a Lisp-0 since symbols, functions, and strings are all in the same lexical namespace. It's powerful enough that I have an implementation of mal in miniMAL: https://github.com/kanaka/mal/tree/master/impls/miniMAL I mention it because with a trivial yq wrapper, miniMAL code can run source encoded in yaml too:

miniMAL <(yq '.' hello.yaml)
- do
- - prn
  - - "`"
    - "hello"
  - - +
    - 2
    - 3

pez 2024-08-14T07:59:12.917149Z

> I’ve always suspected that a Lisp could be encoded in JSON (thus YAML since JSON is YAML). Lisp code is data, after all. 😃

Ingy döt Net 2024-08-14T14:38:26.750509Z

That's a bit oversimplifying things. Imagine rewriting all your Clojure using only EDN syntax. How would you go about it? That's what miniMAL is doing but for a minuscule subset of Clojure!

Ingy döt Net 2024-08-14T14:40:15.641999Z

To be usable, you need more syntax that you can get out of JSON/EDN. YAML has hidden gems to exploit here. 🙂

Ingy döt Net 2024-08-14T14:43:45.310489Z

To me an interesting aspect of it is that YS is first parsed (not loaded) as YAML. A YAML parser turns YAML text into a stream of 10 different events (typed structs of information). So that's what YS gets to work with and decided what means what.

Ingy döt Net 2024-08-14T14:49:15.675439Z

A new language designer gets to work with a stream of characters. Endless possibilities but also endless decisions required to make. YS has only YAML events, limited but quite useful. JSON has a maps, vecs, strings, nums, bools, and nil. So minimal. At least EDN adds keywords (and comments!) 😄

pez 2024-08-14T14:58:23.535859Z

Yeah, my comment was very much tongue in cheek. > Imagine rewriting all your Clojure using only EDN syntax. How would you go about it? To me Clojure syntax and EDN syntax look very similar. But I am not a language designer.

Ingy döt Net 2024-08-14T15:08:52.337799Z

@pez, sometime (in your copious spare time) try rewriting https://github.com/BetterThanTomorrow/calva/blob/published/src/cljs-lib/src/js_cljs/core.cljs in EDN for me. 😉

Ingy döt Net 2024-08-14T15:10:56.452239Z

Looking over https://github.com/edn-format/edn EDN adds a pretty big handful of things over JSON.

Ingy döt Net 2024-08-14T15:11:39.455089Z

@clojurians115 ednMAL? 😉

Joel Martin 2024-08-14T16:44:00.535359Z

@ingy Haha, that's just Clojure minus reader macros and minus regex and plus tagged types. Or to put it another way, EDN is the round-trippable part of Clojure syntax.

Joel Martin 2024-08-14T16:49:09.732429Z

Here is my first pass at ednMAL (higher than most other Lisps on the homoiconicity scale) 😈:

user=> (require '[clojure.edn :as edn]) (loop [] (let [l (do (print "> ") (flush) (read-line))] (when l (println (pr-str (eval (edn/read-string l)))) (recur))))
> (+ 2 3)
5
> ( (fn [a b] (* a b)) 7 8)
56

🤩 1
Ingy döt Net 2024-08-14T19:30:37.174569Z

> Haha, that's just Clojure minus reader macros and minus regex and plus tagged types. @clojurians115 derp, I totally spaced that EDN was that capable.

$ ys -pe 'clojure::edn/read-string("'\''foo")'
'foo

Ingy döt Net 2024-08-14T19:37:40.591099Z

iirc it's why ys compilation doesn't compile its anonymous function syntax to clojure's anonymous function syntax.

$ ys -ce '\(%1 * (%2 % %3))'
(fn [& [_1 _2 _3]] (*_ _1 (rem _2 _3)))
I use edn/read-string in my test files to compare expected ASTs (encoded in YAML) so #() wouldn't work.

delon 2024-08-16T17:05:46.335209Z

It's great seeing how far you've come! The exorcism examples are illuminating.

🙏 1
Ingy döt Net 2024-08-16T18:56:59.723759Z

@delon exercism (like exercise) not exorcism (like demons)

Ingy döt Net 2024-08-16T18:57:46.454779Z

not sure that was the best name choice for them, but I guess a little cringe helps people remember it 😄

😂 1
pez 2024-08-16T18:58:32.581029Z

Is it #exercism we’re talking about?

Ingy döt Net 2024-08-16T18:59:27.427129Z

Ah cool! Thanks @pez!

Ingy döt Net 2024-08-16T18:59:44.343429Z

I'll have to announce there when I launch.

Ingy döt Net 2024-08-16T19:00:28.188799Z

actually I might have some questions about expectations for them

pez 2024-08-16T19:10:30.652969Z

I think @porkostomus can help you with expectations. He’s been in rather close contact with the core Exercism team, iiuc.

✅ 1
pez 2024-08-16T19:25:05.617279Z

I think #announcements is the place to announce a YAML Exercism track, btw.

Ingy döt Net 2024-08-16T19:26:33.393139Z

and there of course. (YAML*Script*) 🙂

pez 2024-08-16T19:27:36.223879Z

Yeah, haha.

Ingy döt Net 2024-08-13T19:57:26.127679Z

Interesting. That's exactly what I didn't want YS to look like. I wanted programmers to like coding it.

ys -c <(echo '

!yamlscript/v0
say "Hello": 2 + 3

')
(say "Hello" (+_ 2 3))
I had no idea when I started if that was going to be possible. I would have not done it if I thought it wasn't possible... History: • Thought of a YS concept in summer 2022, got the domain name etc • Decided to learn Lisp in Early 2023, found mal • Finished mal in Perl in 2 weeks • Wrote my solution in YAML and kept trying things to see if it could be made pretty • Decided I could but it was really a small project on top of Lingy my continuation of mal to make a full Clojure on Perl • Gave a talk on Lingy and YAMLScript in July 2023 https://www.youtube.com/watch?v=9OcFh-HaCyI@pez from here invited me to here • Found out about SCI and GraalVM native-image; dropped Lingy; learned how to program in Clojure; went full-bore into YS

Ingy döt Net 2024-08-13T19:57:51.611299Z

SPOILER ALERT: This link contains all the current solutions and test files for the upcoming YS exercism track. (They are public in a public repo anyway) This is a good way to review a bunch of real YS programs as the language sits today... https://gist.github.com/ingydotnet/aebc6d93f284394ddc861ff78a4e84ec I'm very happy with almost all of it. But also interested in suggestions!

Ingy döt Net 2024-08-13T19:58:15.955069Z

I should mention that almost all new ideas I get for YS come from programming in it. Just like that first time I ported my perl mal code to YAML 😄

Ingy döt Net 2024-08-13T19:58:42.956619Z

YAML has all these "features" in the spec that normal users don't bother with. Having invented YAML I know all the nuances and put them to good use in YS. I've always suspected that a Lisp could be encoded in JSON (thus YAML since JSON is YAML). And I've made project DSL ASTs from JSON in the past. There's these various parts of YAML that allow it to be turned into a fairly clean looking programming language, but its not immediately obvious even to me. It's been a fun problem to work on...

Ingy döt Net 2024-08-13T19:59:10.886649Z

(didn't realize I wasn't threaded there...)