TMTOWTDI for YS Expressions
Like I said before, in YS, There's More Than One Way To Do It.
This is especially true for YS expressions.
Later on you'll learn that YS is a Lisp in disguise. In Lisp, an expression is a list consisting of a function and its arguments inside a set of parentheses.
Consider this Python code:
name = "World"
print("Hello, " + name + "!")
In a Lisp, this would be written as:
(def name "World")
(println (str "Hello, " name "!"))
In YS, this could be written as:
name =: 'World'
say: str('Hello, ' name '!')
I say could because... TMTOWTDI!
Today I'm going to show you many of the ways to DO IT in YS.
How YS Relates to YAML🔗
The first thing to remember is that all YS code has to be 100% valid YAML. So essentially we need to be able to write any possible Lisp code as YAML!
Since YS wants to be clean like YAML is clean, it offers you several ways to write the same Lisp expression, make it look clean and still be valid YAML.
Note
The YS compiler's first job is to "parse" the YAML input. "Parse" doesn't mean the entire operation of turning YAML into a data structure. YAML calls that operation "loading" and it consists of many steps, the first of which is to "parse" the YAML into a stream of events (structs).
The YS compiler is literally a YAML loader. Writing a YAML parser is by far the most complex part of writing a YAML loader, so YS uses a third-party parser for that part. Therefore anything that is not valid to that parser is not valid YS code! We'll talk about the YS compiler in detail later this summer.
YS only uses YAML block mappings (the normal indented mapping style) and YAML scalars to represent code.
Handy Tip
If you ever see a YAML block sequence (the stuff that starts with -
) or a
YAML flow collection (the {...}
or [...]
stuff), it's not YS "code",
it's just normal YAML"data".
In other words that YS node is in "data mode" not "code mode".
In code mode, a mapping is a set of expressions, where each key/value pair is an expression.
Consider this YS code:
$ ys -e '
name =: "World"
say:
str: "Hello, ", name, "!"
'
Compile error: while parsing a block mapping
in reader, line 5, column 3:
str: "Hello, ", name, "!"
^
expected <block end>, but found ','
in reader, line 5, column 17:
str: "Hello, ", name, "!"
What went wrong?
Look at this code as regular YAML. You can't have any text after a double quoted string, right? This is a parser error.
To get around this, YS has a special escape character.
+ "Hello, " + name + "!"
turns that whole value code into a plain (unquoted)
YAML scalar.
The +
is removed and the rest gets compiled as part of an expression.
Let's try again:
$ ys -e '
name =: "World"
say:
str: + "Hello, ", name, "!"
'
Hello, World!
Better.
Commas Aside🔗
Time to let you in on a little secret.
In YS code, Commas are Whitespace!
The commas separating the arguments above were not necessary.
$ ys -e '
name =: "World"
say:
str: "Hello, " name "!"
'
Hello, World!
Commas are necessary in YAML flow collections though.
It is idiomatic YS to not use commas in code mode unless they really add clarity.
That way, when you do see commas, you'll know you are likely in data mode.
More Ways to Do It🔗
Let's look at several ways to write that "say Hello World" expression.
$ ys -e '
name =: "World"
# Block form
say:
str: + "Hello, " name "!"
# Lisp form
say: (str "Hello, " name "!")
# YS call form
say: str("Hello, " name "!")
# Chained form
=>: str("Hello, " name "!").say()
# Chained colon form
=>: str("Hello, " name "!"):say
# Tag function form
=>: !:say
str: + "Hello, " name "!"
# Or
=>: !:say
str("Hello, " name "!")
'
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
I'll explain each of these forms more as we go.
For now, 2 things.
foo:bar:baz
is shorthand for foo.bar().baz()
.
You can optionally use :xyz
instead of .xyz()
when chaining a function call
that takes no arguments.
And what's the =>
thing?
Remember, YS is YAML and we are in a YAML block mapping.
We can't use expressions where some are key/value pairs and some are plain
scalars.
When we have something that is just a scalar, we can make it a pair by adding
the =>
placeholder key.
OK! It's time to get on with my Summer weekend!
See you next time!