Control flow¶
At the moment, avalon provides two means of controlling the flow of a program, namely if the if
conditional and the while
loop.
In the future, the switch
conditional and the for
loop will be added.
Conditional statements¶
Conditional statements control the flow of the program allowing the program to choose which path the execution is to take depending on the whether a specific condition is fulfilled.
At the moment, only the if
conditional is implemented. It allows execution branching based on comparison between values
and based on whether values match through pattern matching.
If conditional¶
The if
conditional is made of the main branch introduced by if
, optional multiple elif
branches
and an optional else
branch.
Let us first demonstrate how an if
statement can be used to perform branching using comparison.
import io
-- we create a user global variable
var user = (
name = "John Doe",
age = 32
)
-- the program entry point
def __main__ = (val args : [string]) -> void:
-- we perform branching depending on the age of the user
if user.age < 18:
Io.println(user.name + " is a minor.")
elif user.age >= 18 and user.age < 65:
Io.println(user.name + " is an adult in education, employment or training.")
elif user.age >= 65 and user.age < 120:
Io.println(user.name + " is a senior retiring or retired.")
else:
Io.println(user.name + ", may you live another 120 years!")
As mentionned before, the if
statement can also be used to do pattern matching. We are going to adapt the previous example
to one that work with pattern matching using a user defined type.
import io
-- our user type
type user = ():
User(
name : string,
age : int,
alive: bool
)
-- the program entry point
def __main__ = (val args : [string]) -> void:
var u = User(
name = "John Doe",
age = 32,
alive = True
)
-- we begin by matching against the user so we get the user details
if u === User(
name = n:string, -- the type instance must occur when capturing values
age = a:int,
alive = _ -- we use the underscore to let the compiler know that we are not interested in the <alive> field
):
-- now we can use the capture values
if a < 18:
Io.println(n + " is a minor.")
elif a >= 18 and a < 65:
Io.println(n + " is an adult in education, employment or training.")
elif a >= 65 and a < 120:
Io.println(n + " is a senior retiring or retired.")
else:
Io.println(n + ", may you live another 120 years!")
else:
-- this branch will never execute because the type only has one value constructor and we are matching against it
Io.println("We didn't get a valid user!")
That is pretty much all there is to the if
conditional statement.
Loop statements¶
Loop statements allow us to execute the same code multiple times until we decide to stop loop using either a break
or return
statement if the condition is not met already.
Only the while
loop is currently implemented but the for
loop is in the works as well to allow range based looping.
While loop¶
A while
loop allows the looping to continue until the condition is no longer met or the loop is stopped using a break
or a return
statement.
Pattern matching expressions can also figure as condition to loops and this will be demonstrated with a search example at the end of this section.
For the moment, let us see how to implement FizzBuzz.
import io
def __main__ = (val args : [string]) -> void:
-- the buzz counter
var buzzer = 1
-- we keep looping so long as the buzzer is less than 101
while buzzer < 101:
-- We print "Fizz" or "Buzz" or "FizzBuzz" or the number depending on our divisor
if buzzer % 15 == 0:
Io.println("FizzBuzz")
elif buzzer % 3 == 0:
Io.println("Fizz")
elif buzzer % 5 == 0:
Io.println("Buzz")
else:
Io.println(string(buzzer))
-- we don't forget to increment the buzzer else we end up with infinite loop
buzzer = buzzer + 1
-- we end execution
return
Example that combines conditional statements and loops¶
We are going to implement a generic linear search that uses comparison based conditional and pattern matching looping. The function itself is not complicated but combines different elements of what features in the documentation so if you are having trouble understanding the code, look in the reference.
import io
-[
search
Performs a linear search of the needle inside the given list.
:params
- list : [a*]
A generic list of elements to search.
- needle : a*
A generic element to search.
:returns
- index : maybe(a*)
`Just(i)` where `i` is the index where the needle was found,
`None` if no element was found.
]-
def search : a = (val list : [a], val needle : a) -> maybe(int):
-- the current index and the element at that index
var index = 0,
current = list[index]
-- perform the search
-- notice how we are using pattern matching in the while loop itself
while current === Just(value:a):
if needle == value:
return Just(index)
else:
index = index + 1
current = list[index]
-- if we reach here, the needle wasn't found
return None:maybe(int)
-[
main
The main entry point.
:params
- args : [string]
A list of strings that were passed to the program as commandline arguments.
:returns
- nothing : void
]-
def __main__ = (val args : [string]) -> void:
-- search data
val list = [1, 2, 3, 4],
needle = 2
-- we perform the search
var result = search(list, needle)
-- we use pattern matching to see if we found the value and print the index where is was found
if result === Just(index:int):
Io.println("Found element <" + string(needle) + "> at index <" + string(index) + ">.")
else:
Io.println("Element <" + string(needle) + "> not found.")
-- we are done
return