7. Conditional branch

7.1. Syntax to define conditional branch

ATS can define a conditional branch using if, like as the other programming language. The syntax is following:

if CONDITION then EXPRESSION_A else EXPRESSION_B

The CONDITION should be a value of bool type. Also, the EXPRESSION_A and EXPRESSION_B should be typed with same type, that becomes the type of the whole conditional branch expression.

Let’s write some code using if keyword.

1
2
3
4
5
6
7
8
9
(* File: if_then_else.dats *)
#include "share/atspre_staload.hats"

implement main0 () = {
  val a  = if true  then 1 else 2
  val b  = if false then 1 else 2
  val () = println! (a:int)
  val () = println! (b:int)
}
$ patscc if_then_else.dats
$ ./a.out
1
2

The execution result is able to understand for us. BTW, why needs some type assignments such like println! (a:int)? Type inference on ATS language can’t understand type of everything. Sometimes we should tell the type inferencer the type of values.

We can also write any values of bool type at CONDITION.

1
2
3
4
5
6
7
8
9
(* File: if_then_else2.dats *)
#include "share/atspre_staload.hats"

implement main0 () = {
  val a  = if 1 < 2  then 3 else 4
  val b  = if 3 + 4 < 5 then 1 else 2
  val () = println! (a:int)
  val () = println! (b:int)
}
$ patscc if_then_else2.dats
$ ./a.out
3
2

Line number 5 of the code if_then_else2.dats has the type drawn following figure:

_images/if_then_else2.png

However, a compile error occurs with writing a value of the other type at CONDITION.

1
2
3
4
5
6
7
(* File: if_not_bool.dats *)
#include "share/atspre_staload.hats"

implement main0 () = {
  val a  = if 1 then 2 else 3
  val () = println! (a:int)
}
$ patscc if_not_bool.dats
/home/kiwamu/doc/ATS_Foundations/source/code/conditional/if_not_bool.dats: 105(line=5, offs=15) -- 106(line=5, offs=16): error(3): the dynamic expression cannot be assigned the type [S2Ecst(bool_t0ype)].
/home/kiwamu/doc/ATS_Foundations/source/code/conditional/if_not_bool.dats: 105(line=5, offs=15) -- 106(line=5, offs=16): error(3): mismatch of static terms (tyleq):
The actual term is: S2Eapp(S2Ecst(g1int_int_t0ype); S2Ecst(int_kind), S2Eintinf(1))
The needed term is: S2Ecst(bool_t0ype)
patsopt(TRANS3): there are [1] errors in total.
exit(ATS): uncaught exception: _2home_2kiwamu_2src_2ATS_2dPostiats_2src_2pats_error_2esats__FatalErrorExn(1025)

It’s caused with the following type error:

_images/if_not_bool.png

And also, type check error occurs while the type of EXPRESSION_A is different from the type of EXPRESSION_B.

1
2
3
4
5
6
(* File: different_expr.dats *)
#include "share/atspre_staload.hats"

implement main0 () = {
  val a  = if 3 + 4 > 5 then 1 else 2.0
}
$ patscc different_expr.dats
/home/kiwamu/doc/ATS_Foundations/source/code/conditional/different_expr.dats: 130(line=5, offs=37) -- 133(line=5, offs=40): error(3): the dynamic expression cannot be assigned the type [S2EVar(4140)].
/home/kiwamu/doc/ATS_Foundations/source/code/conditional/different_expr.dats: 130(line=5, offs=37) -- 133(line=5, offs=40): error(3): mismatch of static terms (tyleq):
The actual term is: S2Eapp(S2Ecst(g0float_t0ype); S2Ecst(double_kind))
The needed term is: S2EVar(4140)
patsopt(TRANS3): there are [1] errors in total.
exit(ATS): uncaught exception: _2home_2kiwamu_2src_2ATS_2dPostiats_2src_2pats_error_2esats__FatalErrorExn(1025)
_images/different_expr.png

We can write println! in EXPRESSION_A or EXPRESSION_B.

1
2
3
4
(* File: println_expr.dats *)
#include "share/atspre_staload.hats"

implement main0 () = if 7 > 5 then println! "It's true." else ()
$ patscc println_expr.dats
$ ./a.out
It's true.
_images/println_expr.png

The part else EXPRESSION_B is optional, if type of the EXPRESSION_A is void.

1
2
3
4
(* File: println_without_else.dats *)
#include "share/atspre_staload.hats"

implement main0 () = if 7 > 5 then println! "It's true."

Note

Exercise: What type is assigned on following conditional branch? Or, where is a type error issue on the expression?

  1. if 2 < 1 then 3 else 4
  2. if "true" then 3.14 else 2.72
  3. if not (3 = 4) then 1 < 2 else 1 > 2
  4. if println! "false" then true else false

7.2. Conditional branch is also an expression

Let’s see following code:

1
2
3
4
5
6
7
(* File: duplicate_code.dats *)
#include "share/atspre_staload.hats"

fun f (x:int): int = if x < 30 then 10 + x * 10
                               else 10 + x * 100

implement main0 () = println! (f 20)
$ patscc duplicate_code.dats
$ ./a.out
210

The code is runnable. However, the codes 10 + x * are duplicated.

_images/duplicate_code.png

We can avoid the duplication, because conditional branch is also an expression.

1
2
3
4
5
6
7
(* File: duplicate_code.dats *)
#include "share/atspre_staload.hats"

fun f (x:int): int = 10 + x * ((if x < 30 then 10
                                          else 100):int)

implement main0 () = println! (f 20)
$ patscc no_duplicate_code.dats
$ ./a.out
210

The right side of the operator * should be assigned with the type int, because the oprator is defined as templates such as taking int while conditional branch doesn’t have simple type int.

Note

Exercise: Write function ampm that take o’clock and return either forenoon or afternoon.

Note

Exercise: Write function constellation that take month and day as birthday and return constellation of the birthday.