yamlscript

Ingy döt Net 2024-05-20T16:07:18.473539Z

@markus.agwin I finally got the PR done: https://github.com/kloimhardt/LisRoot/pull/1 Adds simple make commands:

make docker-generate
make docker-runall
make open OPENER=...
make clean
etc

Markus Agwin 2024-05-22T08:58:08.427739Z

Your notation clarifies a lot for me. I understand now that higher order functions of the Lisp form ((f 1) "a" 3) translate best to f(1) 'a': 3 (= syntaxA). Previously I considered two different notations: syntaxB) avoid parentheses at all using apply and syntaxC) use S-expression to denote higher order functions. I learned that one should not be afraid of parentheses in YS as long as they are used within YES-expressions. But I ask myself how the higher-higher Lisp form (((f 1) 2) "a" 3) translates best to YS. This higher-higher form occurs in @sritchie09’s Emmy algebra system which will be a cornerstone in replacing Python by YS in science :-). This is why I considered S-exprs (respectively apply) in the first place for higher order fns. So the questing remains: how to best translate this higher-higher form to YS?

Ingy döt Net 2024-05-22T13:18:00.931219Z

Let's work through some real examples. Are you at keyboard?

Markus Agwin 2024-05-22T13:18:27.008629Z

yes

Ingy döt Net 2024-05-22T13:20:03.429039Z

Cool. I made this for a starter:

!yamlscript/v0

defn f:
  (x): \(x * %1)
  (x y):
    f: x * y

say:
  f(6): 7

say:
  f(6 2): 7
compiles to:
$ ys x.ys -c
(defn f ([x] (fn [& [_1]] (*_ x _1))) ([x y] (f (*_ x y))))
(say ((f 6) 7))
(say ((f 6 2) 7))
evals to:
$ ys x.ys
42
84

Ingy döt Net 2024-05-22T13:20:51.757129Z

I don't think we've discussed multi-arity functions yet. I think the syntax is pretty awesome.

Ingy döt Net 2024-05-22T13:21:33.336319Z

Perfect higher order example functions don't jump to mind for me so maybe you can help

Ingy döt Net 2024-05-22T13:22:05.787109Z

that one is HO at arity-1

Ingy döt Net 2024-05-22T13:23:08.472479Z

but not sure how to make a chainable real example like your:

(((f 1) 2) "a" 3)

Ingy döt Net 2024-05-22T13:23:30.914509Z

iow, define your f please 🙂

Markus Agwin 2024-05-22T13:26:08.347469Z

an existing example from Emmy (i.e. the SICM book): if you complete the puzzle https://kloimhardt.github.io/cljtiles.html?page=97 you get the following code

(((Lagrange-equations (L-free-particle
                        'm))
   (literal-function 'q))
  't)

Ingy döt Net 2024-05-22T13:30:19.765699Z

Was looking for something simple that we could show all the code for here, then discuss various ways to call it.

Ingy döt Net 2024-05-22T13:31:18.776929Z

But I can just riff on (((f 1) 2) "a" 3) without defining f I suppose...

Markus Agwin 2024-05-22T13:35:21.970599Z

The most usual case in Emmy is (((f 1 2) 3) 4) let's assume (defn f [a b] (fn [c] (fn [d] (+ a b c d)))

Ingy döt Net 2024-05-22T13:36:56.366759Z

ok, thx. sec

Markus Agwin 2024-05-22T13:52:13.235749Z

I have:

#!/usr/bin/env ys-0

defn f(a b):
     fn(c):
      fn(d): (a + b + c + d)

say: (((f 1 2) 3) 4)

say:
  apply:
    apply:
      f: 1 2
      list: 3
    list: 4

Ingy döt Net 2024-05-22T13:53:12.307099Z

I have this so far:

!yamlscript/v0

defn f(a b):
  fn(c): \(+ a b c %1)

say: (((f 1 2) 3) 4)

say: ((f(1 2) 3) 4)

say: f(1 2).apply([3]).apply([4])

# say: f(1 2).eval(3).eval(4)

Ingy döt Net 2024-05-22T13:55:26.842119Z

I think I can make this work pretty easily:

say: f(1 2).(3).(4)

Ingy döt Net 2024-05-22T13:56:34.072319Z

Which I like because the . operator inserts the LHS as the first arg for the RHS expression

Ingy döt Net 2024-05-22T13:58:42.593749Z

like in

$ ys -e 'say: (5 ..  15).nth(5)'
10

Ingy döt Net 2024-05-22T13:59:33.116059Z

(but normally in that specific case you would:

$ ys -e 'say: (5 ..  15).5'
10

Markus Agwin 2024-05-22T14:04:17.305309Z

I think the f(1 2).(3).(4) is confusing. Maybe add a call function to ys which works like in JS?

👍 1
Ingy döt Net 2024-05-22T14:04:19.149309Z

In Clojure if you have (def x '(+ 1 2)) how do you evaluate x to get 3?

Markus Agwin 2024-05-22T14:06:11.351359Z

(eval x)

Ingy döt Net 2024-05-22T14:08:28.519359Z

!yamlscript/v0

defn f(a b):
  fn(c): \(+ a b c %1)

say: (((f 1 2) 3) 4)

say: ((f(1 2) 3) 4)

say: f(1 2).apply([3]).apply([4])

defn call [f & xs]: apply(f xs)

say: f(1 2).call(3).call(4)

Ingy döt Net 2024-05-22T14:08:57.251349Z

$ ys x.ys
10
10
10
10

Ingy döt Net 2024-05-22T14:09:48.416759Z

defn call(f & xs): apply(f xs) currently mis-compiles 😞

Ingy döt Net 2024-05-22T14:09:55.911459Z

will fix

Ingy döt Net 2024-05-22T14:10:12.067489Z

but yeah I can add to ys::std

Ingy döt Net 2024-05-22T14:12:37.570009Z

for completeness:

!yamlscript/v0

defn f(a b):
  fn(c): \(+ a b c %1)

say: (((f 1 2) 3) 4)

say: ((f(1 2) 3) 4)

say: f(1 2).apply([3]).apply([4])

defn call [f & xs]: apply(f xs)

say: f(1 2).call(3).call(4)

say:
  call:
    call:
      f: 1 2
      =>: 3
    =>: 4

Markus Agwin 2024-05-22T14:12:51.733089Z

To be fair: I thought for some time how to express (((f 1 2) 3) 4) and that case is, I think, the real reason why S-exprs stuck around for such a long time. Can't be beaten. My best proxy ist the JS call. Or, and this is the outstanding speciality of YS: recommend to use S-exprs when it comes to higher order functions.

Markus Agwin 2024-05-22T14:14:19.736869Z

I find this last example without any parentheses very nice.

Ingy döt Net 2024-05-22T14:14:20.888009Z

Well my first thought was:

f(1 2)(3)(4)

Ingy döt Net 2024-05-22T14:15:12.611549Z

which you could make a good YeS argument for, and is nicer than S to my eyes

Ingy döt Net 2024-05-22T14:15:36.788299Z

But yeah, higher order S is fine 🙂

Ingy döt Net 2024-05-22T14:18:00.754319Z

I can see the benefits of Lisp only having one way to do it, from both the learners side and the language side. But I'm a TMTOWTDI kind of person, and thus YS is as well...

Markus Agwin 2024-05-22T14:18:01.500379Z

I repeat that I think this

say:
  call:
    call:
      f: 1 2
      =>: 3
    =>: 4
I the very best solution I ever saw for this problem.

Ingy döt Net 2024-05-22T14:19:03.157419Z

Cool. That's what I like to hear. Because for me I would never do that one. But YS is flexible enough for both of us 🙂

Markus Agwin 2024-05-22T14:20:23.160089Z

because the two call: at the beginning clearly indicates that a twice nested higher order function will follow. And then the actual call is very compact and readable.

👍 1
Ingy döt Net 2024-05-22T14:20:29.468629Z

BTW, I appreciate your bring this up because while refactoring the ytranslation.yaml file I realized that some things I wanted to do didn't work (yet).

Ingy döt Net 2024-05-22T14:21:10.045099Z

Certainly the call is most readable form...

Ingy döt Net 2024-05-22T14:21:43.331539Z

I guess depends who your audience is.

Ingy döt Net 2024-05-22T14:22:33.853039Z

I'm used to writing libraries where I don't expect many end users to look. People who do look can grok tighter code more easily.

Ingy döt Net 2024-05-22T14:23:12.101519Z

I'll add call now before I forget 😄

👍 1
Markus Agwin 2024-05-22T14:24:43.663599Z

The f().call().call() is for OO programmers. Your staggered call syntax can be intriguing for Python mathematicians because the call does not disturb the calculation-notation.

Ingy döt Net 2024-05-22T14:27:46.519499Z

One thing that bothers me about the . operator is that inserting into the 1st position is the wrong place for so many functions.

a-list.take(5)  # wrong
a-list.take(5 _)  # _ specifies where to put the arg, so works

Ingy döt Net 2024-05-22T14:28:33.514489Z

but I hate: • needing the _ at all • remembering arg order for multi arg core functions

Ingy döt Net 2024-05-22T14:31:05.454069Z

that's why:

$ ys -e 'a-list.take(5)' -c
(__ a-list (list +take 5))
Certain functions like take compile to +take which runtime checks arg type and DTRT Slower but painless. If speed ever matters, you can be explicit:
$ ys -e 'a-list.take(5 _)' -c
(__ a-list (list take 5 '_))

Ingy döt Net 2024-05-22T14:33:06.815049Z

I think of Clojure as pretty low-level and performant and purposefully close to Java and I do love that about it. But I don't mind making speed tradeoffs in YS when it makes programming easier.

Ingy döt Net 2024-05-22T14:34:30.050869Z

Also speaking of OO, there are a couple dozen big parts of YS that haven't even been broached yet. One is good OO.

Ingy döt Net 2024-05-22T14:34:57.331419Z

Happy to hear suggestions if anyone has them...

Ingy döt Net 2024-05-22T14:35:22.718289Z

Looked briefly at CLOS. Not sure how well it fits into Clojure

Markus Agwin 2024-05-22T14:42:10.037279Z

• I can only add my two cents here: there is a precise reasoning in the Clojure design concerning the issue whether a core function expects important data in the first or last arg position. I only forgot how the reasoning is exactly. But there is a blog post somewhere and the specialists certainly know. I only remember that there is a reason why one writes (conj coll x) but (cons x seq) . Has to do with sequences vs collections.

Ingy döt Net 2024-05-22T14:43:58.080599Z

Yeah, I was watching a super old Rich interview this morning about various collections, their performance and how conj applies well to all.

Ingy döt Net 2024-05-22T14:47:51.380629Z

But it's a constant struggle for me to remember arg order and types. And while I love Clojure (and its ecosystem) for what it offers me to accomplish things I've been marinating on for 20 years, I'm on the opposite side of those who want to use it for everything 🙂 iow, I don't study Clojure to have it be ingrained for a long time...

Ingy döt Net 2024-05-22T14:49:34.381209Z

At some point I'm going to start writing parts of YS in YS. Maybe the ys::std lib first. But I also realize at this point it doesn't do much for me or ys to do so...

Ingy döt Net 2024-05-22T14:50:07.502119Z

I have already started writing the repo tooling scripts in YS though.

Ingy döt Net 2024-05-22T14:50:21.458659Z

Anyway back to your blog post idea....

Ingy döt Net 2024-05-22T14:50:53.885739Z

I love the idea. Would you be interesting in collaborating on the post?

Markus Agwin 2024-05-22T14:54:18.775699Z

Sure I'd like to contribute. Question is: what? I already put everything I have into the ArXiv paper. I just wanted a post where Docker and the stuff I (and most scientists) do not understand can be learned about.

Ingy döt Net 2024-05-22T15:16:06.406859Z

> A first step towards this would be: a small (few lines) blog post about 1) this --cpp idea and 2) your already existing Docker container for CERN's ROOT (did you use their container for this?). It could be one entry point to gauge a possible interest-level also in communities not used to Slack-channels. Such a blog post is in any case much less effort than immediately including a YS->C compiler. Things I'd like to cover: • Your LisRoot demo repo • How it uses Docker so everyone can enjoy right away (compiling root crashed my (very new and capable) laptop twice!) • How YAMLScript might be a better language than Python for this root stuff. Things I'd like to do before posting: • Finish the basic user docs (so interested people can play quickly) • Add the trivial --cpp option • Make a few improvements to the docker thing (I know how to make this awesome) • Probably need to tweak the blog setup to monitor traction and also to point people to the best forums for further exploration YS needs to find some early super-fans. This might help. I really could use your help explaining why Clojure (with YS lipstick) is foundationally better for this kind of stuff than Python. I strongly feel that YS/Clojure is (potentially) better than Python for most things, but I don't have the words for it yet... I like what you wrote here: https://github.com/kloimhardt/LisRoot?tab=readme-ov-file#why-yamlscript Makes me feel like your help would give the post a lot higher chance of connecting to the intended audience.

Markus Agwin 2024-05-22T15:31:57.383919Z

I am myself desperately searching for words to explain to my formerly-fellow scientists that notation also matters in coding and not only in math. And I think YAMLScript itself, being a new notation, enhances the available syntax considerably to this end. So: I will add an extended README.md to my LisRoot repository, it will basically be taken from the first part of the old ArXiv paper, but the code not in Clojure but in YAMLScript syntax. Then we'll see how it can be used in a YS blogpost.

Ingy döt Net 2024-05-22T15:35:51.614189Z

Sounds good. I think between us we can work on the words, and also have a good feeling if it hits the mark. I do think that syntax/notation matters, but I also think that immutability and FP matters here, but I'm at a loss to explain exactly why...

Markus Agwin 2024-05-22T15:47:19.756309Z

Well, 1) calculation on paper and thus math is intrinsically a notation for immutable objects/entities/thingies. Putting this argument upside-down: if a programming-language (PL) is immutable, it suits best for math people. (BTW: Googles JAX makes Python immutable.) 2) Math formulas are expressions. If a PL is expression based (not statement based) -> good 3) Basic objects of math are functions (e.g. sin(x)) and operators (i.e. Integration operator). Now: operator is just another name for higher order function. If a PL is functional -> good

Markus Agwin 2024-05-24T14:58:05.806569Z

I wrote a draft. https://github.com/kloimhardt/LisRoot/blob/main/paper/why_ys.md It focuses on point (2) above (= expressions better than statements). Point (1) (= pure functions, immutability) cannot be shown with LisRoot as it obviously is meant for C++ object mutation. And point (3) (= higher order functions) is best demonstrated with YAMLScript+Emmy (in LisRoot higher order does not play a big role). Putting all 3 aspects into one post is too much anyway, they are completely distinct and independent.

Ingy döt Net 2024-05-24T16:23:10.842939Z

Nice! Today is a travel day for me and I have a ton of menial tasks to do. I'll try to take a look at the airport or when I arrive to Madrid.

👍 1
Ingy döt Net 2024-05-20T16:08:46.412039Z

I also refactored https://github.com/ingydotnet/LisRoot/blob/main/ytranslation.yaml quite a bit. Interested to hear how you like it.

Ingy döt Net 2024-05-20T16:13:13.957689Z

While working on @markus.agwin’s LisRoot with YS stuff, I've been thinking it should be easy to add a ys --cpp option to compile YS directly to C++.

🔥 1
Markus Agwin 2024-05-22T09:27:39.662829Z

A first step towards this would be: a small (few lines) blog post about 1) this --cpp idea and 2) your already existing Docker container for CERN's ROOT (did you use their container for this?). It could be one entry point to gauge a possible interest-level also in communities not used to Slack-channels. Such a blog post is in any case much less effort than immediately including a YS->C compiler.

Ingy döt Net 2024-05-22T13:26:03.770729Z

> (did you use their container for this?) Yes. https://github.com/ingydotnet/LisRoot/blob/be8ec84a6dbccf61b0d83d746db2a315f9df40df/Dockerfile#L1

Ingy döt Net 2024-05-22T13:26:28.576839Z

The c++ would just be a shell out to ferret. Simple.