#> Hi! Welcome to the Nulan tutorial. After reading this, you #> should have a very basic idea of how to write Nulan programs. #> To start with, all Nulan programs are composed of zero or #> more expressions. Every expression must have a value. The #> process of taking an expression and returning a value is #> called "evaluation". #> The simplest expressions are literals, which evaluate to #> themself: 5 #> Try clicking on the above expression `5`. In the lower-right #> panel, you can see that it evaluates to the number `5`. #> Another type of literal is a string: "I'm a string" #> Strings start with ", contain zero or more characters, and #> end with ". They're used for storing text. #> Let's try something more complicated: 5 + 10 #> If you click on the above expression, you'll see it evaluates #> to the number `15`. That expression is composed of three #> parts: the number `5`, the symbol `+`, and the number `10`. #> Now, something I haven't told you yet is that all these #> examples are fully interactive. To try it out, go ahead and #> change the expression `5 + 10` to anything you like, and the #> lower-right panel will automatically update with the answer. #> Any changes you make are automatically saved, so you can #> close this tab and reopen it later. #> If at any time you want to undo the changes you've made, #> click the "Reset Tutorial" button at the top of the screen. #> Be careful, it will wipe out your changes, and you can't get #> them back. #> Nulan also supports some more math stuff with the usual #> priority: 1 + 2 * 3 / 4 - 5 #> And you can use parentheses to change the priority of any #> expression: (1 + 2) * 3 / (4 - 5) #> Let's talk about boxes. A box is something that can hold a #> single value. It can then be unboxed later. To create a box, #> you use the `box` symbol: box foo = 2 #> What we've done here is taken the number `2` and placed it #> inside a box. We then took that box and assigned it to the #> symbol `foo`. We can then unbox it by simply using the symbol #> `foo`: foo #> You might have noticed that the `box` expression evaluated to #> `()`. Every expression needs to return a value, but some #> expressions don't have anything meaningful to return, so they #> return `()` instead. #> Because everything in Nulan is an expression, symbols can #> be used as part of a bigger expression: foo + 2 #> But boxes aren't just a shorthand for referring to values. #> Right now, the `foo` box contains the number `2`. But we can #> put a different number into the box: foo <= 5 #> Now the `foo` box contains the number `5` rather than the #> number `2`. It is like as if we unboxed it, took the number #> out, put a new number in, and then reboxed it again. #> But even though the stuff inside the box changed, the box #> itself is the same. This will be important later on. #> Let's talk about functions. Functions are extremely common in #> Nulan, so it's important to understand them. A function is a #> value that can be called with multiple expressions as #> arguments and then returns an expression. #> It's okay if you didn't understand anything I just said. I'll #> take it slow and use lots of examples. First, to create a #> function, you use the `->` symbol: -> a a #> The above expression returns a function which accepts a #> single argument called `a`. It then returns `a`. Let's try #> calling the function: (-> a a) 5 #> One way of thinking about this is to imagine that Nulan #> replaced the symbol `a` inside the function with the number #> `5`, then returned `5`. #> The parentheses are needed because without them, Nulan would #> treat it as a function that accepts two arguments and always #> returns `5`. #> Let's write a function that takes any number and adds `10` to #> it: -> a (a + 10) #> And now let's call it: (-> a (a + 10)) 5 #> Nulan replaced `a` with `5`, and then returned `(5 + 10)`. #> This probably doesn't seem very useful. Let's make it more #> useful by taking the function and placing it into a box: box add = -> a (a + 10) #> We created a function using `-> a (a + 10)` and then used #> `box` to assign it to the `add` symbol. #> This is common enough that Nulan has a special `def` symbol #> which is almost exactly like `box`, except that it works #> better for functions: def add -> a (a + 10) #> Now let's call it: add 5 add 10 add 15 #> Notice that we called it three times, with a different #> argument each time. In the first call, `a` was replaced with #> `5`, in the second it was replaced with `10`, and in the #> third it was replaced with `15`. #> Let's make a function that accepts three arguments and adds #> them together: def add -> a b c a + b + c #> Now let's call it: add 1 2 3 #> Nulan replaced `a` with `1`, `b` with `2`, and `c` with `3`, #> then returned `1 + 2 + 3`. #> That was a simple example, but functions can become quite #> complex. The reason why functions are so useful is that they #> let you easily evaluate an expression multiple times. #> Consider these three expressions: 1 + 2 * 3 / 10 1 + 2 * 4 / 10 1 + 2 * 5 / 10 #> The only difference between them is that the first uses `3`, #> the second uses `4`, and the third uses `5`. Using boxes #> won't help with the code duplication. Functions to the #> rescue! def foo -> a 1 + 2 * a / 10 foo 3 foo 4 foo 5 #> Now the parts that remain unchanged are put into the #> function. The only part that changes is the argument `a`, #> which is replaced when the function is called. #> And so, functions let you take the unchanging parts and put #> them into a single place, which makes it much much easier as #> your programs become bigger and more complex. #> Moving on, let's look at this program: w/box temp = 5 if temp temp + 1 w/box temp = 10 if temp temp + 2 #> The `w/box` symbol is like `box` but the box it creates can #> only be accessed inside the `w/box` expression. #> The `if` symbol checks if its first argument is true. If it #> is, then it will evaluate the second argument. Otherwise #> it will evaluate the third argument. #> This pattern of creating a temporary box and using `if` is #> quite common. Let's try using a function to get rid of the #> code duplication: def if-box -> x y if x x + y if-box 5 1 if-box 10 2 #> This works, but it's not very flexible. What if we wanted to #> subtract the numbers, or divide the numbers, or do something #> else? The `if-box` function will only add, nothing else. #> One of the cool things about functions is that because they #> are values, they can be used as arguments to other functions: def if-box -> x f if x f x if-box 5 -> x (x + 1) if-box 10 -> x (x + 2) #> Here's what happened. We called `if-box` with two arguments: #> the number `5` and the function `-> x (x + 1)`, which were #> then replaced like usual. #> This works, but it's a bit verbose. Let's use a macro to #> remove the verbosity! You've already seen a bunch of macros, #> but you didn't realize it. These are all macros: #> `+` `-` `*` `/` `box` `=` `<=` `->` `def` `w/box` `if` #> What is a macro? Well, a function has arguments, which are #> replaced with values, and the function then returns a value. #> A macro is a special kind of function that has arguments, #> which are replaced with code, and the macro then returns #> code. #> First, to create a macro, we use the `$mac` macro: $mac if-box -> #> The above expression took the empty function `->`, converted #> it into a macro, and then assigned it to the symbol `if-box`. #> But this macro doesn't do anything yet. Let's start by #> copying in our original program: $mac if-box -> w/box temp = 5 if temp temp + 1 #> We can't use this macro just yet, though. Remember when I #> said that macros are given code and return code? Well, right #> now the macro is returning a value, not code. If we use the #> `'` macro, we tell Nulan to treat it as code rather than a #> value: $mac if-box -> 'w/box temp = 5 if temp temp + 1 #> Oops, Nulan is saying that the symbol `temp` is undefined. #> What happened?! #> Well, do you remember when I said earlier that you can change #> the value of a box without changing the box itself? The `'` #> macro returns boxes, not symbols. And the `temp` box isn't #> defined. #> To fix this, we'll need to assign `temp` to a box. To create #> a box, we can use the `w/uniq` macro: $mac if-box -> w/uniq temp 'w/box temp = 5 if temp temp + 1 #> And now it works just fine. But it only works for the first #> use case, not the second. Let's figure out the parts that #> change: those parts will need to be arguments to the macro. #> Well, the expression `5` changes, so let's replace that with #> an argument: $mac if-box -> x w/uniq temp 'w/box temp = x if temp temp + 1 #> And the expression `1` changes too, so let's add another #> argument: $mac if-box -> x y w/uniq temp 'w/box temp = x if temp temp + y #> And now we can use it like so: if-box 5 1 if-box 10 2 #> But wait a minute, this looks just like earlier, when we were #> using a function. The reason for using a macro is so that we #> don't hardcode the `+` symbol, so let's start by getting rid #> of that: $mac if-box -> x y w/uniq temp 'w/box temp = x if temp y #> Now, you might be tempted to use it like this: if-box 5 temp + 1 if-box 10 temp + 2 #> But as you can see, that doesn't work. The reason is because #> inside the macro, we used `w/uniq` to create a new box, but #> that box is only accessible *inside* the macro. Instead, #> let's use a symbol: $mac if-box -> x y w/box temp = sym "it" 'w/box temp = x if temp y #> We used the `sym` function to create a new symbol and then #> inserted that rather than a box. And now we can use the macro #> like this: if-box 5 it + 1 if-box 10 it + 2 #> Inside the `if-box` expression, you can use the symbol `it` #> to refer to the first argument of `if-box`. As you can see, #> this is indeed shorter than using a function. #> Because macros always return code, anything you can do with #> macros, you can do by manually writing the code yourself. #> The benefit of macros is that you don't *have* to write the #> code yourself: you can have the macro write the code for you. #> And so, by using macros wisely, you can write shorter, more #> readable code. #> Now, with that out of the way, let's do something fun! div style border-radius "5px" opacity "1" width "50px" height "50px" background-color "green" on "click" -> alert "I'm green!" div style border-radius "5px" opacity "0.5" width "50px" height "50px" background-color "red" position "relative" top "-25px" left "25px" on "click" -> alert "I'm red!" #> If you look in the upper-right panel, you should see two #> boxes. If you click on them, they'll tell you what color they #> are. Both of the boxes were generated with the above code. #> If you change the code, it'll change the boxes. Try it out!
#> 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 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 340 341 if-box 10 342 temp + 2 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! | |