Control Flow
YS (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 YS 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 YS 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
:
!YS-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 YS 2
1) YS
2) YS
If a program does not define a main
function, then nothing will happen unless
you've defined a top level function call yourself.
YS 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 YS (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 named then
and else
words for grouping, but do
can also be used.
Looping Functions and Recursion🔗
YS 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 YS 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🔗
YS has a few common conditional expressions: if
, when
, cond
and case
.
The if
Function🔗
In YS, 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🔗
YS 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'