Control Flow
YAMLScript (iow Clojure) is a functional programming language. That means that everything is a function. Running a program is just a calling a function that calls other functions.
Even though YAMLScript tries hard to look like an imperative language, you must keep in mind that it's functional and get familiar with how the flow works.
This document will cover:
- Starting a program
- Variable scope
- Grouping expressions
- Looping functions and recursion
- Conditional expressions
Note: Some of the things that are called "functions" in in this document are actually "macros" or "special forms" in Clojure. The distinction is not particularly important here, but worth mentioning.
Starting a Program
A YAMLScript file generally is just a bunch of defn
calls to define functions.
Sometimes there will be assignment expressions at the top level. Top level variables are global and can be used anywhere in the program. They belong to the file's namespace which is main
by default.
If a program defines a function called main
, it will be called when the program is run. Any command line arguments will be passed to the main
function after being cast to numbers if they look like numbers.
program.ys
:
!yamlscript/v0
defn main(word='Hello!' times=3):
each i (1 .. times):
say: "$i) $word"
$ ys program.ys
1) Hello!
2) Hello!
3) Hello!
$ ys program.ys YAMLScript 2
1) YAMLScript
2) YAMLScript
If a program does not define a main
function, then nothing will happen unless you've defined a top level function call yourself. YAMLScript files that are meant to be used as libraries will not have a main
function or a top level function call.
Variable Scope
One cool thing about YAMLScript (and Clojure) is that you can use any word as a variable name. Even things like if
and for
which are reserved words in many languages.
For example you might do this:
defn foo(list):
count =: count(list)
if count > 0:
say: 'The list is not empty'
else:
say: 'The list is empty'
Once we bind count
to the result of the count
function, we can't use the count
function again in that scope. Often this is just fine. And it feels nice that you don't have to think up a synonym or alternative mangling for count
.
Grouping Expressions
Some expression contexts allow multiple expressions to be grouped together and some only allow a single expression.
You can group multiple expressions together with a do
function call when you need to to do multiple things in a context that only allows a single expression.
if a > b:
do:
say: 'a is greater than b'
say: 'a must be HUGE!'
say: 'Nothing to see here'
Note: The
if
function actually supports the better namedthen
andelse
words for grouping, butdo
can also be used.
Looping Functions and Recursion
YAMLScript has a few looping functions: loop
, reduce
, for
and each
.
These will be documented in more detail in the future, but for now you can see the Clojure documentation for them:
- loop
- reduce
- for
each
is a YAMLScript function that calls to afor
expression inside adoall
expression. This allows you to print things in the loop body. In every other way it's the same asfor
.
Conditional Expressions
YAMLScript has a few common conditional expressions: if
, when
, cond
and case
.
The if
Function
In YAMLScript, an if
expression is a function that takes 3 arguments: a condition, a then expression and an else expression.
if a: b c # If a is true, return b, else return c
The b
and c
expressions can also be mapping pairs:
if a:
say: 'yes'
say: 'no'
Sometimes you want to do more than one thing in the then or else expression:
if a:
then:
say: 'yes'
say: 'yes'
else:
say: 'no'
say: 'no'
If you use then
you must also use else
, but else
can be used without a then
:
if a:
say: 'yes'
else:
say: 'no'
say: 'no'
Since if
is a function, it has a return value.
say:
if a: -'yes' 'no'
Any variable assigned in the then
or else
expression will only apply to that expression and not to the surrounding scope.
x =: 1
if a > b:
x =: 2
x =: 3
=>: x # => 1
What you want to do here is capture the result of the if
expression:
x =:
if a > b:
then: 2
else: 3
=>: x # => 2 or 3
Note that say
returns nil
, so all the if
expressions above would also return nil
.
The when
Function
YAMLScript also has a when
function that is like if
but without an else expression.
when a:
say: 'yes'
The if
function should only be used wen you have a then and an else expression. Otherwise, use when
.
One thing about when
is that its body can have multiple expressions.
when a:
say: 'yes'
say: 'yes'
The cond
Function
The cond
function is like a series of if
expressions but with multiple conditions.
size =:
cond:
a < 20: 'small'
a < 50: 'medium'
a < 100: 'large'
else: 'huge'
The case
Function
The case
function is like a cond
but with a single expression to compare against.
count =:
case a:
1: 'one'
2: 'two'
3: 'three'
else: 'many'