#>  Hi! Welcome to the Nulan tutorial. After reading this, you
1
 
#>  Hi! Welcome to the Nulan tutorial. After reading this, you
2
#>  should have a very basic idea of how to write Nulan programs.
3
 
4
#>  To start with, all Nulan programs are composed of zero or
5
#>  more expressions. Every expression must have a value. The
6
#>  process of taking an expression and returning a value is
7
#>  called "evaluation".
8
 
9
#>  The simplest expressions are literals, which evaluate to
10
#>  themself:
11
 
12
5
13
 
14
#>  Try clicking on the above expression `5`. In the lower-right
15
#>  panel, you can see that it evaluates to the number `5`.
16
 
17
#>  Another type of literal is a string:
18
 
19
"I'm a string"
20
 
21
#>  Strings start with ", contain zero or more characters, and
22
#>  end with ". They're used for storing text.
23
 
24
#>  Let's try something more complicated:
25
 
26
5 + 10
27
 
28
#>  If you click on the above expression, you'll see it evaluates
29
#>  to the number `15`. That expression is composed of three
30
#>  parts: the number `5`, the symbol `+`, and the number `10`.
31
 
32
#>  Now, something I haven't told you yet is that all these
33
#>  examples are fully interactive. To try it out, go ahead and
34
#>  change the expression `5 + 10` to anything you like, and the
35
#>  lower-right panel will automatically update with the answer.
36
 
37
#>  Any changes you make are automatically saved, so you can
38
#>  close this tab and reopen it later.
39
 
40
#>  If at any time you want to undo the changes you've made,
41
#>  click the "Reset Tutorial" button at the top of the screen.
42
#>  Be careful, it will wipe out your changes, and you can't get
43
#>  them back.
44
 
45
#>  Nulan also supports some more math stuff with the usual
46
#>  priority:
47
 
48
1 + 2 * 3 / 4 - 5
49
 
50
#>  And you can use parentheses to change the priority of any
51
#>  expression:
52
 
53
(1 + 2) * 3 / (4 - 5)
54
 
55
#>  Let's talk about boxes. A box is something that can hold a
56
#>  single value. It can then be unboxed later. To create a box,
57
#>  you use the `box` symbol:
58
 
59
box foo = 2
60
 
61
#>  What we've done here is taken the number `2` and placed it
62
#>  inside a box. We then took that box and assigned it to the
63
#>  symbol `foo`. We can then unbox it by simply using the symbol
64
#>  `foo`:
65
 
66
foo
67
 
68
#>  You might have noticed that the `box` expression evaluated to
69
#>  `()`. Every expression needs to return a value, but some
70
#>  expressions don't have anything meaningful to return, so they
71
#>  return `()` instead.
72
 
73
#>  Because everything in Nulan is an expression, symbols can
74
#>  be used as part of a bigger expression:
75
 
76
foo + 2
77
 
78
#>  But boxes aren't just a shorthand for referring to values.
79
#>  Right now, the `foo` box contains the number `2`. But we can
80
#>  put a different number into the box:
81
 
82
foo <= 5
83
 
84
#>  Now the `foo` box contains the number `5` rather than the
85
#>  number `2`. It is like as if we unboxed it, took the number
86
#>  out, put a new number in, and then reboxed it again.
87
#>  But even though the stuff inside the box changed, the box
88
#>  itself is the same. This will be important later on.
89
 
90
#>  Let's talk about functions. Functions are extremely common in
91
#>  Nulan, so it's important to understand them. A function is a
92
#>  value that can be called with multiple expressions as
93
#>  arguments and then returns an expression.
94
 
95
#>  It's okay if you didn't understand anything I just said. I'll
96
#>  take it slow and use lots of examples. First, to create a
97
#>  function, you use the `->` symbol:
98
 
99
-> a a
100
 
101
#>  The above expression returns a function which accepts a
102
#>  single argument called `a`. It then returns `a`. Let's try
103
#>  calling the function:
104
 
105
(-> a a) 5
106
 
107
#>  One way of thinking about this is to imagine that Nulan
108
#>  replaced the symbol `a` inside the function with the number
109
#>  `5`, then returned `5`.
110
 
111
#>  The parentheses are needed because without them, Nulan would
112
#>  treat it as a function that accepts two arguments and always
113
#>  returns `5`.
114
 
115
#>  Let's write a function that takes any number and adds `10` to
116
#>  it:
117
 
118
-> a (a + 10)
119
 
120
#>  And now let's call it:
121
 
122
(-> a (a + 10)) 5
123
 
124
#>  Nulan replaced `a` with `5`, and then returned `(5 + 10)`.
125
 
126
#>  This probably doesn't seem very useful. Let's make it more
127
#>  useful by taking the function and placing it into a box:
128
 
129
box add = -> a (a + 10)
130
 
131
#>  We created a function using `-> a (a + 10)` and then used
132
#>  `box` to assign it to the `add` symbol.
133
 
134
#>  This is common enough that Nulan has a special `def` symbol
135
#>  which is almost exactly like `box`, except that it works
136
#>  better for functions:
137
 
138
def add -> a (a + 10)
139
 
140
#>  Now let's call it:
141
 
142
add 5
143
 
144
add 10
145
 
146
add 15
147
 
148
#>  Notice that we called it three times, with a different
149
#>  argument each time. In the first call, `a` was replaced with
150
#>  `5`, in the second it was replaced with `10`, and in the
151
#>  third it was replaced with `15`.
152
 
153
#>  Let's make a function that accepts three arguments and adds
154
#>  them together:
155
 
156
def add -> a b c
157
  a + b + c
158
 
159
#>  Now let's call it:
160
 
161
add 1 2 3
162
 
163
#>  Nulan replaced `a` with `1`, `b` with `2`, and `c` with `3`,
164
#>  then returned `1 + 2 + 3`.
165
 
166
#>  That was a simple example, but functions can become quite
167
#>  complex. The reason why functions are so useful is that they
168
#>  let you easily evaluate an expression multiple times.
169
#>  Consider these three expressions:
170
 
171
1 + 2 * 3 / 10
172
 
173
1 + 2 * 4 / 10
174
 
175
1 + 2 * 5 / 10
176
 
177
#>  The only difference between them is that the first uses `3`,
178
#>  the second uses `4`, and the third uses `5`. Using boxes
179
#>  won't help with the code duplication. Functions to the
180
#>  rescue!
181
 
182
def foo -> a
183
  1 + 2 * a / 10
184
 
185
foo 3
186
 
187
foo 4
188
 
189
foo 5
190
 
191
#>  Now the parts that remain unchanged are put into the
192
#>  function. The only part that changes is the argument `a`,
193
#>  which is replaced when the function is called.
194
 
195
#>  And so, functions let you take the unchanging parts and put
196
#>  them into a single place, which makes it much much easier as
197
#>  your programs become bigger and more complex.
198
 
199
#>  Moving on, let's look at this program:
200
 
201
w/box temp = 5
202
  if temp
203
    temp + 1
204
 
205
w/box temp = 10
206
  if temp
207
    temp + 2
208
 
209
#>  The `w/box` symbol is like `box` but the box it creates can
210
#>  only be accessed inside the `w/box` expression.
211
 
212
#>  The `if` symbol checks if its first argument is true. If it
213
#>  is, then it will evaluate the second argument. Otherwise
214
#>  it will evaluate the third argument.
215
 
216
#>  This pattern of creating a temporary box and using `if` is
217
#>  quite common. Let's try using a function to get rid of the
218
#>  code duplication:
219
 
220
def if-box -> x y
221
  if x
222
    x + y
223
 
224
if-box 5  1
225
if-box 10 2
226
 
227
#>  This works, but it's not very flexible. What if we wanted to
228
#>  subtract the numbers, or divide the numbers, or do something
229
#>  else? The `if-box` function will only add, nothing else.
230
 
231
#>  One of the cool things about functions is that because they
232
#>  are values, they can be used as arguments to other functions:
233
 
234
def if-box -> x f
235
  if x
236
    f x
237
 
238
if-box 5  -> x (x + 1)
239
if-box 10 -> x (x + 2)
240
 
241
#>  Here's what happened. We called `if-box` with two arguments:
242
#>  the number `5` and the function `-> x (x + 1)`, which were
243
#>  then replaced like usual.
244
 
245
#>  This works, but it's a bit verbose. Let's use a macro to
246
#>  remove the verbosity! You've already seen a bunch of macros,
247
#>  but you didn't realize it. These are all macros:
248
#>  `+` `-` `*` `/` `box` `=` `<=` `->` `def` `w/box` `if`
249
 
250
#>  What is a macro? Well, a function has arguments, which are
251
#>  replaced with values, and the function then returns a value.
252
#>  A macro is a special kind of function that has arguments,
253
#>  which are replaced with code, and the macro then returns
254
#>  code.
255
 
256
#>  First, to create a macro, we use the `$mac` macro:
257
 
258
$mac if-box ->
259
 
260
#>  The above expression took the empty function `->`, converted
261
#>  it into a macro, and then assigned it to the symbol `if-box`.
262
#>  But this macro doesn't do anything yet. Let's start by
263
#>  copying in our original program:
264
 
265
$mac if-box ->
266
  w/box temp = 5
267
    if temp
268
      temp + 1
269
 
270
#>  We can't use this macro just yet, though. Remember when I
271
#>  said that macros are given code and return code? Well, right
272
#>  now the macro is returning a value, not code. If we use the
273
#>  `'` macro, we tell Nulan to treat it as code rather than a
274
#>  value:
275
 
276
$mac if-box ->
277
  'w/box temp = 5
!undefined symbol: temp
278
     if temp
279
       temp + 1
280
 
281
#>  Oops, Nulan is saying that the symbol `temp` is undefined.
282
#>  What happened?!
283
 
284
#>  Well, do you remember when I said earlier that you can change
285
#>  the value of a box without changing the box itself? The `'`
286
#>  macro returns boxes, not symbols. And the `temp` box isn't
287
#>  defined.
288
 
289
#>  To fix this, we'll need to assign `temp` to a box. To create
290
#>  a box, we can use the `w/uniq` macro:
291
 
292
$mac if-box ->
293
  w/uniq temp
294
    'w/box temp = 5
295
       if temp
296
         temp + 1
297
 
298
#>  And now it works just fine. But it only works for the first
299
#>  use case, not the second. Let's figure out the parts that
300
#>  change: those parts will need to be arguments to the macro.
301
 
302
#>  Well, the expression `5` changes, so let's replace that with
303
#>  an argument:
304
 
305
$mac if-box -> x
306
  w/uniq temp
307
    'w/box temp = x
308
       if temp
309
         temp + 1
310
 
311
#>  And the expression `1` changes too, so let's add another
312
#>  argument:
313
 
314
$mac if-box -> x y
315
  w/uniq temp
316
    'w/box temp = x
317
       if temp
318
         temp + y
319
 
320
#>  And now we can use it like so:
321
 
322
if-box 5  1
323
if-box 10 2
324
 
325
#>  But wait a minute, this looks just like earlier, when we were
326
#>  using a function. The reason for using a macro is so that we
327
#>  don't hardcode the `+` symbol, so let's start by getting rid
328
#>  of that:
329
 
330
$mac if-box -> x y
331
  w/uniq temp
332
    'w/box temp = x
333
       if temp
334
         y
335
 
336
#>  Now, you might be tempted to use it like this:
337
 
338
if-box 5
339
  temp + 1
!undefined symbol: temp
340
 
341
if-box 10
342
  temp + 2
!undefined symbol: temp
343
 
344
#>  But as you can see, that doesn't work. The reason is because
345
#>  inside the macro, we used `w/uniq` to create a new box, but
346
#>  that box is only accessible *inside* the macro. Instead,
347
#>  let's use a symbol:
348
 
349
$mac if-box -> x y
350
  w/box temp = sym "it"
351
    'w/box temp = x
352
       if temp
353
         y
354
 
355
#>  We used the `sym` function to create a new symbol and then
356
#>  inserted that rather than a box. And now we can use the macro
357
#>  like this:
358
 
359
if-box 5
360
  it + 1
361
 
362
if-box 10
363
  it + 2
364
 
365
#>  Inside the `if-box` expression, you can use the symbol `it`
366
#>  to refer to the first argument of `if-box`. As you can see,
367
#>  this is indeed shorter than using a function.
368
 
369
#>  Because macros always return code, anything you can do with
370
#>  macros, you can do by manually writing the code yourself.
371
 
372
#>  The benefit of macros is that you don't *have* to write the
373
#>  code yourself: you can have the macro write the code for you.
374
#>  And so, by using macros wisely, you can write shorter, more
375
#>  readable code.
376
 
377
#>  Now, with that out of the way, let's do something fun!
378
 
379
div
380
  style
381
    border-radius    "5px"
382
    opacity          "1"
383
    width            "50px"
384
    height           "50px"
385
    background-color "green"
386
 
387
  on "click" ->
388
    alert "I'm green!"
389
 
390
 
391
div
392
  style
393
    border-radius    "5px"
394
    opacity          "0.5"
395
    width            "50px"
396
    height           "50px"
397
    background-color "red"
398
 
399
    position         "relative"
400
    top              "-25px"
401
    left             "25px"
402
 
403
  on "click" ->
404
    alert "I'm red!"
405
 
406
#>  If you look in the upper-right panel, you should see two
407
#>  boxes. If you click on them, they'll tell you what color they
408
#>  are. Both of the boxes were generated with the above code.
409
#>  If you change the code, it'll change the boxes. Try it out!