# Expressions

_Expressions_ are the basis of programming in Ava. An expression is some code
that will produce a _value_ when evaluated.

## Syntax

Functions contain expressions. Expressions take the form of:

- Literal Values
- Variable Definitions
- Variable References
- Function Calls
- Control Structures

## Control Structures

### If Then

The `if/then` expression expects an expression that returns a _Boolean Value_.
That expression is evaluated. If it evaluates to `true`, the `then` expression
is evaluated. Otherwise the `else` expression is evaluated.

```
if <boolean expr> then <expr> else <expr>
```

### Match

```
match <expr>
    case <pattern> => <expr>
end match
```

### Do/Return

The `do/return` expression allows for imperative composition of monadic
expressions. It works with any types that are members of `Monad` or `BiMonad`.

#### Do/Return for Monad

Each step of the `do` is defined by an expression that produces a Monad. The
syntax desugars to `fmap` calls, where `return` is a `map` call.

```
fn foo: () => Option[Int32]
    1
end fn

fn bar: () => Option[Int32]
    2
end fn

fn baz: () => Option[Int32]
    3
end fn

let example: Option[Int32] :=
    do
        x <- foo()
        y <- bar()
        _ <- baz()
    return
        x + y
    end do

assert(example == Some(3))
```

#### Do/Return for BiMonad

The `BiMonad` is right biased, where the "left" side is assumed to represent
some error case. The typical use case for this behavior is the `IO[E, A]` type.

```
fn foo: () => IO[String, Int32]
    sync(1)
end fn

fn bar: () => IO[String, Int32]
    sync(2)
end fn

fn baz: () => IO[String, Int32]
    sync(3)
end fn

let program: IO[String, Int32] :=
    do
        x <- foo()
        y <- bar()
        _ <- baz()
    return
        x + y
    end do

program ->
    sum => assert(sum == 3)
```