# 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 then else ``` ### Match ``` match case => 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) ```