aboutsummaryrefslogtreecommitdiff
path: root/documentation/book
diff options
context:
space:
mode:
authorEduardo Julian2021-07-29 19:23:23 -0400
committerEduardo Julian2021-07-29 19:23:23 -0400
commit54b28c1caeda08965c258411a32229be1766d47f (patch)
treeee0eecd3a009f80e716f2c3c07095bc80d3b70bb /documentation/book
parent5d4583aebd00adced10275b32ff1a93ab418be50 (diff)
Switched from the "from to" convention to the "minimum additional" convention.
Diffstat (limited to 'documentation/book')
-rw-r--r--documentation/book/the_lux_programming_language/chapter_3.md2
-rw-r--r--documentation/book/the_lux_programming_language/chapter_4.md175
2 files changed, 176 insertions, 1 deletions
diff --git a/documentation/book/the_lux_programming_language/chapter_3.md b/documentation/book/the_lux_programming_language/chapter_3.md
index 33400b355..08187fdbe 100644
--- a/documentation/book/the_lux_programming_language/chapter_3.md
+++ b/documentation/book/the_lux_programming_language/chapter_3.md
@@ -219,5 +219,5 @@ Also, you might be wondering what's the difference between `List` and `list`. We
Again, we haven't mentioned functions. But if you're impatient to learn about them, just click the link below.
-See you in the next chapter!
+See you in [the next chapter](chapter_4.md)!
diff --git a/documentation/book/the_lux_programming_language/chapter_4.md b/documentation/book/the_lux_programming_language/chapter_4.md
new file mode 100644
index 000000000..8af46ccfc
--- /dev/null
+++ b/documentation/book/the_lux_programming_language/chapter_4.md
@@ -0,0 +1,175 @@
+# Chapter 4: Functions and Definitions
+
+_Where you will learn how to build your own Lux code._
+
+---
+
+OK, so you've seen several explanations and details so far, but you haven't really seen how to make use of all of this information.
+
+No worries. You're about to find out!
+
+First, let's talk about how to make your own functions.
+
+```
+(function (plus_two x) (inc (inc x)))
+```
+
+Here's the first example.
+This humble function increases a `Nat` twice.
+
+What is it's type?
+
+Well, I'm glad you asked.
+
+```
+(: (-> Nat Nat)
+ (function (plus_two x) (inc (inc x))))
+```
+
+That `->` thingie you see there is a macro for generating function types.
+It works like this:
+
+```
+(-> arg1 arg2 ... argN return)
+```
+
+The types of the arguments and the return type can be any type you want (even other function types, but more on that later).
+
+How do we use our function? Just put it at the beginning for a form:
+
+```
+((function (plus_two x) (inc (inc x))) 5)
+## => 7
+```
+
+Cool, but... inconvenient.
+
+It would be awful to have to use functions that way.
+
+How do we use the `plus_two` function without having to inline its definition (like the `debug.log!` function we used previously)?
+
+Well, we just need to define it!
+
+```
+(def: plus_two
+ (: (-> Nat Nat)
+ (function (_ x)
+ (inc (inc x)))))
+```
+
+Or, alternatively:
+
+```
+(def: plus_two
+ (-> Nat Nat)
+ (function (_ x)
+ (inc (inc x))))
+```
+
+Notice how the `def:` macro can take the type of its value before the value itself, so we don't need to wrap it in the type-annotation `:` macro.
+
+Now, we can use the square function more conveniently.
+
+```
+(plus_two 7)
+## => 9
+```
+
+Nice!
+
+Also, I forgot to mention another form of the `def:` macro which is even more convenient:
+
+```
+(def: (plus_two x)
+ (-> Nat Nat)
+ (inc (inc x)))
+```
+
+The `def:` macro is very versatile, and it allows us to define constants and functions.
+
+If you omit the type, the compiler will try to infer it for you, and you will get an error if there are any ambiguities.
+
+You will also get an error if you add the types but there's something funny with your code and things don't match up.
+
+Error messages keep improving on each release, but in general you'll be getting the **file, line and column** on which an error occurs, and if it's a type-checking error, you'll usually get the type that was expected and the actual type of the offending expression... in multiple levels, as the type-checker analyses things in several steps. That way, you can figure out what's going on by seeing the more localized error alongside the more general, larger-scope error.
+
+---
+
+Functions, of course, can take more than one argument, and you can even refer to a function within its own body (also known as recursion).
+
+Check this one out:
+
+```
+(def: (factorial' acc n)
+ (-> Nat Nat Nat)
+ (if (n.= 0 n)
+ acc
+ (factorial' (n.* n acc) (dec n))))
+
+(def: (factorial n)
+ (-> Nat Nat)
+ (factorial' 1 n))
+```
+
+And if we just had the function expression itself, it would look like this:
+
+```
+(function (factorial' acc n)
+ (if (n.= 0 n)
+ acc
+ (factorial' (n.* n acc) (dec n))))
+```
+
+Here, we're defining the `factorial` function by counting down on the input and multiplying some accumulated value on each step. We're using an intermediary function `factorial'` to have access to an accumulator for keeping the in-transit output value, and we're using an `if` expression (one of the many macros in the `library/lux` module) coupled with a recursive call to iterate until the input is 0 and we can just return the accumulated value.
+
+As it is (hopefully) easy to see, the `if` expression takes a _test_ expression as its first argument, a _"then"_ expression as its second argument, and an _"else"_ expression as its third argument.
+
+Both the `n.=` and the `n.*` functions operate on `Nat`s, and `dec` is a function for decreasing `Nat`s; that is, to subtract 1 from the `Nat`.
+
+You might be wondering what's up with that `n.` prefix.
+
+The reason it exists is that Lux's arithmetic functions are not polymorphic on the numeric types, and so there are similar functions for each type.
+
+If you import the module for `Nat` numbers, like so:
+
+```
+(.module
+ [library
+ [lux
+ [math
+ [number
+ ["n" nat]]]]])
+```
+
+You can access all definitions in the "library/lux/math/number/nat" module by just using the "n." prefix.
+
+ I know it looks annoying, but later in the book you'll discover a way to do math on any Lux number without having to worry about types and prefixes.
+
+Also, it might be good to explain that Lux functions can be partially applied. This means that if a function takes N arguments, and you give it M arguments, where M < N, then instead of getting a compilation error, you'll just get a new function that takes the remaining arguments and then runs as expected.
+
+That means, our factorial function could have been implemented like this:
+
+```
+(def: factorial
+ (-> Nat Nat)
+ (factorial' +1))
+```
+
+Or, to make it shorter:
+
+```
+(def: factorial (factorial' +1))
+```
+
+Nice, huh?
+
+---
+
+We've seen how to make our own definitions, which are the fundamental components in Lux programs.
+
+We've also seen how to make functions, which is how you make your programs **do** things.
+
+Next, we'll make things more interesting, with _branching_, _loops_ and _pattern-matching_!
+
+See you in the next chapter!
+