-
Notifications
You must be signed in to change notification settings - Fork 1
Type System
The language has a strong and static type discipline.
A type can be one of the following:
- build-in types : unsigned/signed/floating numbers of different size
- union : can only be one type of the set at a time
- product : tuple-like types where a value of this type hold a value of each type of the product
- function : transforming a type into another
- generic : type depending on another
Example:
// Build-in types // type Int, Float // Union type A = Int | Float -- Product type P = Int Float Int -- Generic type P 'A = 'A -- Function type F = Int -> Float -- Example: -- 2D vector type Vec2 = Float Float -- Maybe with only types, see #Details type Nothing type Just 'A = 'A type Maybe 'A = Nothing | (Just 'A) -- Compose function type type Compose 'A 'B 'C = ('B -> 'C) -> ('A -> 'B) -> 'A -> 'C
Only the necessary types are added:
(U)Byte, (U)Short, (U)Int, (U)Long, Float, Double respectively 1, 2, 4, 8, 4 and 8 bytes long. The U
before integers types specify unsigned version of that type.
A generic type can be recognized by it's bound types prefixed by '
. A function using those use the type inferring to determine them:
let f : 'A -> 'B = ...;
let i : Float = f(42 as Int);
// 'A is Int thanks to the first parameter
// 'B is Float thanks to the type of `i`
Any Type can be implicitly casted to a union type containing this type :
type A = B | C
let b : B = ...;
let a : A = b; // implicit
let a_ : A = A(b); // explicit
Any other conversion must be explicit, either by using a function transforming the value, or by using the constructor:
type Pair = Int Int
let p : Pair = Pair(42, 1337);
The Type of a constructor is a function taking each type in the same order as defined. Union type's constructor need to be casted to use the right version :
let f = A; // error : Can't determined which version used : `B -> A` or `C -> A` // note : Try to cast the constructor to the type you wants let f : B -> A = A; // or let f = A as (B -> A);
A Trait is a set of operations and functions operating in relation to a type. It's useful when an operation require the implementation of the type to be well-defined and/or the operation can't be generalized to all types.
trait Representable of 'A = // It should have at least one type binding
toString : ('A -> String);
define Representable of Bool {
// Implementation depending on the definition of type
// In this case `Bool`
toString (b : Bool) -> String { return if b then "True" else "False"; }
}```
`toString` can then be used in expression:
```hs
let str = toString(True); // "True"
A trait can be used on generics types, can require multiple operations and can provide a default value on those operations.
When defining a generic type you probably wants to constraints this types because not all of them define a trait for example.
let toString2 : 'A -> String where Representable 'A = toString
// toString2 can only be used to type defining the `Representable` trait