|
| 1 | +# Overview |
| 2 | + |
| 3 | +This is an overview of most language features in Reason. It does not explain |
| 4 | +them in detail, but should serve as a quick reference. Please see the guides |
| 5 | +on the left for additional details about each feature. |
| 6 | + |
| 7 | +## Let Bindings |
| 8 | + |
| 9 | +_Details: [Let Bindings](/let-bindings)_ |
| 10 | + |
| 11 | +Feature | Example |
| 12 | +--------------------------------|---------- |
| 13 | +String value | `let hi = "Hello World";` |
| 14 | +Int value | `let count = 42;` |
| 15 | +Type annotation on binding | `let count: int = 42;` |
| 16 | + |
| 17 | +- Note: Let bindings are immutable and cannot change once created. |
| 18 | + |
| 19 | +## Built In Types |
| 20 | + |
| 21 | +_Details: [Primitives](primitives)_ |
| 22 | + |
| 23 | +Feature | Example |
| 24 | +--------------------------------|---------- |
| 25 | +Int | `let x: int = 10;` |
| 26 | +Float | `let x: float = 10.0;` |
| 27 | +Boolean | `let x: bool = false;` |
| 28 | +String | `let x: string = "ten";` |
| 29 | +Char | `let x: char = 'c';` |
| 30 | +Unit | `let x: unit = ();` |
| 31 | +Option | `let x: option(int) = Some(10);` |
| 32 | +Tuple | `let x: (int, string) = (10, "ten");` |
| 33 | +List | `let x: list(int) = [1, 2, 3];` |
| 34 | +Array | <code>let x: array(int) = [|1, 2, 3|];</code> |
| 35 | +Functions | `let x: (int, int) => int = (a, b) => a + b;` |
| 36 | + |
| 37 | +## Strings |
| 38 | + |
| 39 | +_Details: [Strings](primitives#strings)_ |
| 40 | + |
| 41 | +Feature | Example |
| 42 | +--------------------------------|---------- |
| 43 | +String | `"Hello"` |
| 44 | +String concatenation | `"Hello " ++ "World"` |
| 45 | +Character | `'x'` |
| 46 | +Character at index | `let x = "Hello"; x.[2];` |
| 47 | + |
| 48 | +- String Functions: [`module String`](https://reasonml.github.io/api/String.html) |
| 49 | + |
| 50 | +## Numbers |
| 51 | + |
| 52 | +- _Details: [Integer](primitives#integer)_ |
| 53 | +- _Details: [Float](primitives#float)_ |
| 54 | + |
| 55 | +Feature | Example |
| 56 | +--------------------------------|---------- |
| 57 | +Integer | `23`, `-23` |
| 58 | +Integer operations | `23 + 1 - 7 * 2 / 5` |
| 59 | +Integer modulo | `13 mod 2` |
| 60 | +Float | `23.0`, `-23.0` |
| 61 | +Float operations | `23.0 +. 1.0 -. 7.0 *. 2.0 /. 5.0` |
| 62 | +Float exponentiation | `2.0 ** 3.0` |
| 63 | + |
| 64 | +## Booleans and Logical Operators |
| 65 | + |
| 66 | +_Details: [Boolean](primitives#boolean)_ |
| 67 | + |
| 68 | +Feature | Example |
| 69 | +--------------------------------|---------- |
| 70 | +Boolean Values | `true`, `false` |
| 71 | +Comparison | `>`, `<`, `>=`, `<=` |
| 72 | +Boolean operations | `!`, `&&`, <code>||</code> |
| 73 | +Reference equality | `===`, `!==` |
| 74 | +Structural equality | `==`, `!=` |
| 75 | + |
| 76 | +## If-Else Expressions |
| 77 | + |
| 78 | +Feature | Example |
| 79 | +--------------------------------|---------- |
| 80 | +If-Else expressions | `if (condition) { a; } else { b; }` |
| 81 | +Ternary expressions | `condition ? a : b;` |
| 82 | + |
| 83 | +- Note: These are expressions and can be assigned to a variable: |
| 84 | +`let x = if (condition) { a; } else { b; };` |
| 85 | + |
| 86 | +## Functions |
| 87 | + |
| 88 | +_Details: [Functions](functions)_ |
| 89 | + |
| 90 | +Feature | Example |
| 91 | +--------------------------------|---------- |
| 92 | +Function definition | `let divide = (a, b) => a / b;` |
| 93 | +Function calls | `divide(6, 2); // 3` |
| 94 | +Named arguments | `let divide = (~a, ~b) => a / b;` |
| 95 | +Calling named arguments | `divide(~a=6, ~b=2); // 3` |
| 96 | +Named argument punning | `divide(~a, ~b);` |
| 97 | +Recursive functions | `let rec infinite = () => infinite();` |
| 98 | + |
| 99 | +### Advanced Functions |
| 100 | + |
| 101 | +Feature | Example |
| 102 | +--------------------------------|---------- |
| 103 | +Partial application | `let divideTen = divide(10); divideTen(5); // 2` |
| 104 | +Partially applying out of order | `let half = divide(_, 2); half(10); // 5` |
| 105 | +Optional arguments | `let print = (~prefix=?, text) => {...};` |
| 106 | +Optional arguments with default | `let divide = (~a=100, ~b) => a / b;` |
| 107 | +Function chaining (pipe) | <code>32 |> half |> half; // 8</code> |
| 108 | + |
| 109 | +### Function Types |
| 110 | + |
| 111 | +Feature | Example |
| 112 | +--------------------------------|---------- |
| 113 | +Inline typing | `let divide = (a: int, b: int): int => a / b;` |
| 114 | +Standalone type | `type intFn = (int, int) => int;` |
| 115 | +Using standalone type | `let divide: intFn = (a, b) => a / b;` |
| 116 | +Typing optional arguments | `let print = (~prefix: option(string)=?, text) => {...};` |
| 117 | + |
| 118 | +## Implicit Return |
| 119 | + |
| 120 | +There is no `return` keyword in Reason. The last expression in a block or |
| 121 | +function definition is the returned value. |
| 122 | + |
| 123 | +```reasonml |
| 124 | +let twentyThree = () => { |
| 125 | + let x = 10; |
| 126 | + let x = x + 10; |
| 127 | + /* x + 3 is the implicit return of the function. */ |
| 128 | + x + 3; |
| 129 | +}; |
| 130 | +``` |
| 131 | + |
| 132 | +## Basic Structures |
| 133 | + |
| 134 | +_Details: [Basic Structures](basic-structures)_ |
| 135 | + |
| 136 | +Feature | Example |
| 137 | +--------------------------------|---------- |
| 138 | +List (Immutable) | `[1, 2, 3]` |
| 139 | +List add to front | `[a1, a2, ...theRest]` |
| 140 | +List concat | `[a1, a2] @ theRest` |
| 141 | +Array (Mutable) | <code>[|1, 2, 3|]</code> |
| 142 | +Array access | <code>let arr = [|1, 2, 3|]; arr[1];</code> |
| 143 | +Tuples | `(1, "hello")` |
| 144 | + |
| 145 | +- List Functions: [`module List`](https://reasonml.github.io/api/List.html) |
| 146 | +- Array Functions: [`module Array`](https://reasonml.github.io/api/Array.html) |
| 147 | + |
| 148 | +## Maps and Sets |
| 149 | + |
| 150 | +There are several different ways to interact with Maps and Sets depending on the |
| 151 | +specific environment being used. In standard Reason code there are `Map` and |
| 152 | +`Set` modules: |
| 153 | + |
| 154 | +- [`module Map.Make`](https://reasonml.github.io/api/Map.Make.html) |
| 155 | +- [`module Set.Make`](https://reasonml.github.io/api/Set.Make.html) |
| 156 | + |
| 157 | +When using BuckleScript `belt` exposes these modules: |
| 158 | + |
| 159 | +- [`module Belt.Map`](https://bucklescript.github.io/bucklescript/api/Belt.Map.html) |
| 160 | +- [`module Belt.Set`](https://bucklescript.github.io/bucklescript/api/Belt.Set.html) |
| 161 | + |
| 162 | +There are also other libraries that will provide their own implementation of |
| 163 | +these data structures. Check the style guide of the project you are |
| 164 | +working in to determine which module to use. |
| 165 | + |
| 166 | +## Type Annotations |
| 167 | + |
| 168 | +Any expression or argument may include a "type annotation". In most cases, type annotations |
| 169 | +are not necessary and the compiler will infer the types automatically. You may include |
| 170 | +type annotations to verify your own understanding against what the compiler infers. |
| 171 | + |
| 172 | +Feature | Example |
| 173 | +--------------------------------|---------- |
| 174 | +Expression type annotation | `let x = (expression: int)` |
| 175 | +Annotation on let binding | `let x: int = expression;` |
| 176 | +Argument/return value annotation| `let addOne = (a: int): int => a + 1;` |
| 177 | + |
| 178 | +## Type Parameters |
| 179 | + |
| 180 | +Types can be made generic with type parameters. |
| 181 | + |
| 182 | +Feature | Example |
| 183 | +--------------------------------|---------- |
| 184 | +Type parameters | `type pair('a, 'b) = ('a, 'b);` |
| 185 | +Annotation with parameters | `let x: pair(int, string) = (10, "ten");` |
| 186 | +String list | `let x: list(string) = ["Hello", "World"];` |
| 187 | + |
| 188 | +## Records |
| 189 | + |
| 190 | +_Details: [Records](records)_ |
| 191 | + |
| 192 | +Feature | Example |
| 193 | +--------------------------------|---------- |
| 194 | +Record definition | `type t = {foo: int, bar: string};` |
| 195 | +Record creation | `let x = {foo: 10, bar: "hello"};` |
| 196 | +Record access | `x.foo;` |
| 197 | +Record spread | `let y = {...x, bar: "world"};` |
| 198 | +Destructuring | `let {foo, bar} = x;` |
| 199 | +Mutable record fields | `type t = {mutable baz: int}; let z = {baz: 10};` |
| 200 | +Mutable record updates | `z.baz = 23;` |
| 201 | +With type parameters | `type t('a) = {foo: 'a, bar: string};` |
| 202 | + |
| 203 | +- Note: Record types are [nominal](https://en.wikipedia.org/wiki/Nominal_type_system). This means that two different record definitions (`type x = {...};`) with the exact same fields are not compatible. They cannot be used interchangeably and cannot be spread into each other. |
| 204 | + |
| 205 | +## Variants |
| 206 | + |
| 207 | +_Details: [Variants](variants)_ |
| 208 | + |
| 209 | +Variant types model values that may assume one of many known variations. This |
| 210 | +feature is similar to "enums" in other languages, but each variant form may |
| 211 | +optionally specify data that is carried along with it. |
| 212 | + |
| 213 | +Feature | Example |
| 214 | +--------------------------------|---------- |
| 215 | +Variant definition | <code>type t = | Foo | Bar;</code> |
| 216 | +Variants with args | <code>type t = | Foo(string) | Bar(int);</code> |
| 217 | +With type parameters | <code>type t('a) = | One('a) | Two('a, 'a);</code> |
| 218 | +Using a variant | `let x = Two("Hello", "World");` |
| 219 | + |
| 220 | +## Options |
| 221 | + |
| 222 | +_Details: [Options](options)_ |
| 223 | + |
| 224 | +Options are a built-in variant that represent the presence or absence of a |
| 225 | +value. It is similar to the concept of "nullable" values in other languages. Options |
| 226 | +are used often. |
| 227 | + |
| 228 | +Feature | Example |
| 229 | +--------------------------------|---------- |
| 230 | +Definition (already defined) | <code>type option('a) = | None | Some('a);</code> |
| 231 | +Value that is present | `let x = Some("Hello World");` |
| 232 | +Value that is absent | `let y = None;` |
| 233 | + |
| 234 | +## Pattern Matching |
| 235 | + |
| 236 | +Pattern matching is a very powerful feature in Reason. It matches against variants |
| 237 | +and ensures all cases are covered. Start matching using the `switch` keyword: |
| 238 | + |
| 239 | +```reasonml |
| 240 | +switch (foo) { |
| 241 | +| Some(value) => doSomething(value) |
| 242 | +| None => error() |
| 243 | +} |
| 244 | +``` |
| 245 | + |
| 246 | +Feature | Example |
| 247 | +--------------------------------|---------- |
| 248 | +Basic case | <code>| Some(value) => doSomething(value)</code> |
| 249 | +When conditions | <code>| Some(value) when value > 10 => doSomething(value)</code> |
| 250 | +Catch-all case | <code>| _ => doSomething()</code> |
| 251 | +Matching lists | <code>| [a, b, ...rest] => doSomething(rest)</code> |
| 252 | +Matching records | <code>| {foo: value} => doSomething(value)</code> |
| 253 | +Matching literals | <code>| "Hello" => handleHello()</code> |
| 254 | + |
| 255 | +## Unit |
| 256 | + |
| 257 | +The special "unit" value (written `()`) represents something that never has any |
| 258 | +meaningful value (this is distinct from options which may have a value). |
| 259 | +Functions usually indicate that they perform a side effect by returning a unit |
| 260 | +value. |
| 261 | + |
| 262 | +Feature | Example |
| 263 | +--------------------------------|---------- |
| 264 | +Creating a unit | `let x = ();` |
| 265 | +Passing to a function | `fn(a, b, ());` |
| 266 | +Unit as only argument | `let fn = () => 1; fn();` |
| 267 | + |
| 268 | +## Refs |
| 269 | + |
| 270 | +_Details: [Mutable Bindings](mutable-bindings)_ |
| 271 | + |
| 272 | +Refs allow mutable "variables" in your program. They are a thin wrapper around |
| 273 | +a record with a mutable field called `contents`. |
| 274 | + |
| 275 | +Feature | Example |
| 276 | +--------------------------------|---------- |
| 277 | +Type (already defined) | `type ref('a) = {mutable contents: 'a};` |
| 278 | +Ref creation | `let x = ref(10);` or `let x = {contents: 10};` |
| 279 | +Ref access | `x^;` or `x.contents;` |
| 280 | +Ref update | `x := 20;` or `x.contents = 20;` |
| 281 | + |
| 282 | +## Loops |
| 283 | + |
| 284 | +_Details: [Loops](loops.md)_ |
| 285 | + |
| 286 | +Loops are discouraged in most cases. Instead functional programming patterns |
| 287 | +like `map`, `filter`, or `reduce` can usually be used in their place. |
| 288 | + |
| 289 | +Feature | Example |
| 290 | +--------------------------------|---------- |
| 291 | +While | `while (condition) {...}` |
| 292 | +For (incrementing) | `for (i in 0 to 9) {...}` (inclusive) |
| 293 | +For (decrementing) | `for (i in 9 downto 0) {...}` (inclusive) |
| 294 | + |
| 295 | +- Note: There is no `break` or early returns in Reason. Use a ref containing a |
| 296 | +bool for break-like behavior: `let break = ref(false); while (!break^ && condition) {...};` |
| 297 | + |
| 298 | +## Modules |
| 299 | + |
| 300 | +_Details: [Modules](modules)_ |
| 301 | + |
| 302 | +Modules are a way to group types and values. Each Reason file implicitly |
| 303 | +creates a module of the same name. Each `type` definition and `let` binding in |
| 304 | +a module automatically becomes a "member" of that module which can be accessed |
| 305 | +by other modules. Modules can also be nested using the `module` keyword. |
| 306 | + |
| 307 | +Feature | Example |
| 308 | +--------------------------------|---------- |
| 309 | +Module creation | `module Foo = { let bar = 10; };` |
| 310 | +Module member access | `Foo.bar;` |
| 311 | +Module types | `module type Foo = { let bar: int; };` |
| 312 | + |
| 313 | +## Functors |
| 314 | + |
| 315 | +Functors are like functions that create modules. This is an advanced topic |
| 316 | +that can be very powerful. Here is a basic example: |
| 317 | + |
| 318 | +```reasonml |
| 319 | +module type Stringable = { |
| 320 | + type t; |
| 321 | + let toString: (t) => string; |
| 322 | +}; |
| 323 | +
|
| 324 | +module Printer = (Item: Stringable) => { |
| 325 | + let print = (t: Item.t) => { |
| 326 | + print_endline(Item.toString(t)); |
| 327 | + }; |
| 328 | +
|
| 329 | + let printList = (list: list(Item.t)) => { |
| 330 | + list |
| 331 | + |> List.map(Item.toString) |
| 332 | + |> String.concat(", ") |
| 333 | + |> print_endline; |
| 334 | + }; |
| 335 | +}; |
| 336 | +
|
| 337 | +module IntPrinter = Printer({ |
| 338 | + type t = int; |
| 339 | + let toString = string_of_int; |
| 340 | +}); |
| 341 | +
|
| 342 | +IntPrinter.print(10); // 10 |
| 343 | +IntPrinter.printList([1, 2, 3]); // 1, 2, 3 |
| 344 | +``` |
| 345 | + |
| 346 | +## Comments |
| 347 | + |
| 348 | +Feature | Example |
| 349 | +--------------------------------|---------- |
| 350 | +Multiline Comment | `/* Comment here */` |
| 351 | +Single line Comment | `// Comment here` |
0 commit comments