git.iko.soy/rowtype-yoga/purescript-native
on 64bd2db help sign in
231 lines 5.2 kB history raw
1## Whitespace
3Syntax is whitespace sensitive. The general rule of thumb is that declarations which span multiple lines should be indented past the column on which they were first defined on their subsequent lines.
5That is, the following is valid:
7```haskell
8foo = bar(x) +
9 baz(x)
10```
12But this is not:
14```haskell
15foo = bar(x) +
16baz(x)
17```
19## Blocks
21Blocks are collections of statements wrapped in braces `{ ... }`. Blocks must return a value of the same type on every branch of execution.
23The following types of statement are supported:
25- Variable introduction
26- Variable assignment
27- For loops
28- For-each loops
29- While loops
30- If-Then-Else statements
32Here is an example of a power function defined using a block:
34```haskell
35pow n p = {
36 var m = n;
37 for (i <- 0 until p) {
38 m = m * n;
39 }
40 return m;
41 }
42```
44Blocks enable local mutation of their variables, but mutation is not allowed in general. The type system prevents mutable variables from escaping their scope.
46That is, while the example above is valid, the following does not compile:
48```haskell
49incr n = {
50 n = n + 1;
51 return n;
52 }
53```
55The variable `n` is not mutable, and so the assignment in the first line of the `do` block is not allowed.
57This function can be rewritten as follows:
59```haskell
60incr n = {
61 var m = n;
62 m = m + 1;
63 return m;
64 }
65```
67## For Loops
69For loops look like this:
71```haskell
72total = {
73 var n = 0;
74 for (i <- 0 until 10) {
75 n = n + i;
76 }
77 return n;
78 }
79```
81The bounds `0` and `10` are inclusive and exclusive respectively.
83## For-Each Loops
85For each loops loop over the elements in an array using the `Object.forEach` method. A polyfill may be required for some browsers:
87```haskell
88total arr = {
89 var n = 0;
90 foreach (i in arr) {
91 n = n + i;
92 }
93 return n;
94 }
95```
97## While Loops
99The syntax of a while loop is similar to a foreach loop:
101```haskell
102log2 n = {
103 var count = 0;
104 var m = n;
105 while (m > 1) {
106 m = m / 2;
107 count = count + 1;
108 }
109 return count;
110 }
111```
113## If-Then-Else Statements
115Else branches are optional, and may contain further `if` statements, just as in Javascript:
117```haskell
118collatz n = {
119 var count = 0;
120 var m = n;
121 while (m > 1) {
122 if (m % 2 == 0) {
123 m = m / 2;
124 } else {
125 m = m * 3 + 1;
126 }
127 count = count + 1;
128 }
129 return count;
130 }
131```
133## If-Then-Else Expressions
135The `if`, `then` and `else` keywords can also be used to create conditional expressions. In this case, the `else` block is always required.
137For example,
139```haskell
140conditional = if 2 > 1 then "ok" else "oops"
141```
143## Do Notation
145The `do` keyword introduces simple syntactic sugar for monadic expressions.
147Here is an example, using the maybe monad:
149```haskell
150data Maybe a = Nothing | Just a
152instance Monad Maybe where
153 ret = Just
154 (>>=) Nothing _ = Nothing
155 (>>=) (Just a) f = f a
157isEven n | n % 2 == 0 = Just {}
158isEven _ = Nothing
160evenSum a b = do
161 n <- a
162 m <- b
163 let sum = n + m
164 isEven sum
165 ret sum
166```
168`isEven` adds two values of type `Maybe Number` and returns their sum, if the sum is even. If the sum is odd, `evenSum` returns `Nothing`.
170This example illustrates the following aspects of `do` notation:
172- The corresponding type constructor must be an instance of the `Prelude.Monad` type class, which defines the `ret` and `>>=` functions.
173- Statements can have the following form:
174 - `a <- x` which desugars to `m.bind x (\a -> ...)`
175 - `let a = x` which desugars to `(\a -> ...)(x)`
176 - `x` which desugars to `m.bind x (\_ -> ...)` or just `x` if this is the last statement.
178Not illustrated here, but equally valid is the use of a binder on the left hand side of `<-` or `=`. For example:
180```haskell
181test arr = do
182 (x:y:_) <- arr
183 ret (x + y)
184```
186A pattern match failure will generate a runtime exception, just as in the case of a regular `case` statement.
188## Operators
190In addition to the standard operators, user-defined infix operators can be created by enclosing names in parentheses:
192E.g. to create a synonym for string concatenation:
194```haskell
195(<>) = \s1 s2 -> s1 ++ s2
197greeting = "Hello" <> "World!"
198```
200Regular functions can be used as operators by enclosing their names in backticks:
202```haskell
203foo = \x y -> x * y + y
205test = 10 `foo` 20
206```
208Fixity declarations can associate a precedence level, which is a natural number, to a user-defined operator, and specify which way it associates:
210```haskell
211infixl 5 <>
212infixr 7 %%
213```
215## Record Updates
217Properties on records can be updated using the following syntax: `o { key = value, ..., key = value }`
219For example, the following function increments the `foo` property on its argument:
221```haskell
222incr = \o -> o { foo = o.foo + 1 }
223```
225The generated Javascript assumes the existence of a method called `Object.extend` such that `Object.extend(o, p)` takes an object `o` and generates a shallow copy of `o` including the properties of `p`. A simple JQuery implementation of this specification is
227```haskell
228Object.prototype.extend = function(o, p) {
229 return $.extend({}, o, p);
230};
231```