diff options
author | Eduardo Julian | 2021-07-28 04:48:42 -0400 |
---|---|---|
committer | Eduardo Julian | 2021-07-28 04:48:42 -0400 |
commit | 5d4583aebd00adced10275b32ff1a93ab418be50 (patch) | |
tree | 89315e104e2b0ddd6d56f894f01a0575d3078699 /documentation/book/the_lux_programming_language | |
parent | 061fd8a209bbcaffc2bfb850ac6046752a567d50 (diff) |
Re-named List's tags: Nil => End && Cons => Item
Diffstat (limited to 'documentation/book/the_lux_programming_language')
-rw-r--r-- | documentation/book/the_lux_programming_language/chapter_2.md | 4 | ||||
-rw-r--r-- | documentation/book/the_lux_programming_language/chapter_3.md | 223 |
2 files changed, 226 insertions, 1 deletions
diff --git a/documentation/book/the_lux_programming_language/chapter_2.md b/documentation/book/the_lux_programming_language/chapter_2.md index 6f12f9907..d396f0034 100644 --- a/documentation/book/the_lux_programming_language/chapter_2.md +++ b/documentation/book/the_lux_programming_language/chapter_2.md @@ -146,7 +146,9 @@ Suffice it to say that the `debug.log!` function will produce a value of type `A That `(IO Any)` value will then be run by the system at run-time, giving us the result we want. +--- + Now that we've discussed some of the basics of what goes on inside of Lux programs, it's time for us to explore the language in a little bit more depth. -See you in the next chapter! +See you in [the next chapter](chapter_3.md)! diff --git a/documentation/book/the_lux_programming_language/chapter_3.md b/documentation/book/the_lux_programming_language/chapter_3.md new file mode 100644 index 000000000..33400b355 --- /dev/null +++ b/documentation/book/the_lux_programming_language/chapter_3.md @@ -0,0 +1,223 @@ +# Chapter 3: Syntax and Data-Types + +_Where you will learn the what Lux code is made of._ + +--- + +# Syntax for data-types + +* `Bit`s look like this: + +``` +#0 ## false +#1 ## true +``` + +* `Nat`s look like this: + +``` +0 +123 +0456 +123,456,789 +``` + +* `Int`s look like this: + +``` ++0 +-123 ++0456 +-123,456,789 +``` + +* `Rev`s look like this: + +``` +.123 +.04,56 +.7890 +``` + +* `Frac`s look like this: + +``` ++123.456 +-456.7890 ++0.001 +123,456.789 +``` + +* `Text`s look like this: + +``` +"This is a single-line text" +``` + +* `Unit` looks like this: + +``` +[] +``` + +* Variants look like this: + +``` +#Foo +(#Bar 10 +20.0 "thirty") +``` + +* Tuples look like this: + +``` +[123 ["nested" #tuple] true] +``` + +* Records look like this: + +``` +{#name "Lux" #paradigm #Functional #platforms (list #JVM)} +``` + +**Note**: As you can see, commas (`,`) can be used as separators for the numeric literals. + +--- + +From looking at this, we can see a few interesting bits we haven't discussed. + +One is that the hash (`#`) character is overloaded. + +In the last chapter we saw it being used for comments, but now we're seeing it being used as a prefix for _some weird "label" thingies_ (more on that in a moment). + +To avoid reserving many characters for the language, Lux overloads the hash (`#`) character in situations where it can be used unambiguously. That way, most characters can be used by anyone without fear of stepping on the feet of the language. + +--- + +Regarding _those label thingies_ we saw earlier, they're called **tags**, and the reason they're not mentioned as part of Lux's data-types is that they're not really data-types; they're just part of the language syntax. + +They're used as part of the syntax for data-types, but they're not data-types in themselves. + +Also, you can't just use anything you want as a tag, as you first have to declare them. + +We'll talk more about tags a bit later, when we talk about defining types. + +--- + +Also, just from looking at the syntax for unit and tuples, you can see that they look quite similar. The reason is that unit is actually the empty tuple. I know it sounds odd, but for the most part you just have to think of unit as a kind of empty value, considering that it contains no information inside. + + It might sound specially odd that we have an "empty" value at all in the first place, but as it turns out, it's quite useful in a variety of situations. + + You're about to see one of those pretty soon. + +In the section for variants, you can see 2 different alternatives, and you might wonder how do they differ. + +Well, a variant is a pair of a tag and a _single_ value. That's right, I said **single** value; so you might be wondering how come we're associating 3 values with the `#Bar` tag. + +It's pretty simple, actually. Whenever you're trying to create a variant with more than one value, Lux just wraps all the values inside a tuple for you. + +So, `(#Bar 10 +20.0 "thirty")` is the same as `(#Bar [10 +20.0 "thirty"])`. + +Now, you might be thinking: _what's up with that `#Foo` variant?_ + +Well, sometimes you only care about a variant for its tag, and not for any value it may hold (for example, if you're trying to use a variant type as an enumeration). In that case, you'll want to pair the tag with an empty value (since it has to be paired with something). + +That's right! You've just witnessed **unit** value in action and you didn't even know it. If you just write the name of the tag without any parentheses, Lux will stick a **unit** in there for you. + +That means `#Foo` is the same as ``(#Foo [])``. + +--- + +You might have noticed that I mentioned **records** in this chapter, but not in the previous chapter, where I also talked about the basic data-types Lux offers. + +The reason is that records are a bit of a magic trick in Lux. That means records are not really a data-type that's distinct from the other ones. In fact, records just offer you an alternative syntax for writing tuples. + +That's right! `{#name "Lux" #paradigm #Functional #platforms (list #JVM)}` could mean the same as `["Lux" #Functional (list #JVM)]`, depending on the ordering imposed by the tags. + +--- + +Remember when I said that you needed to declare your tags? Well, depending on the order in which you declare them, that means that `#name` could point to the first element in the tuple, or to another position entirely. Also, in the same way that tags have a numeric value when it comes to their usage in tuples/records, that's also the case for variants. + +For example, the `List` type has two tags: `#.End` and `#.Item`. The `#.End` tag has value 0, while the `#.Item` tag has value 1. That's what allows Lux to the able to identify which option it is working with at runtime when you're dealing with variants. + +Tags belong to the module in which they were declared, and you must use the module name (or an alias) as a prefix when using tags. That is why I've written `#.End` and `#.Item`, instead of `#End` and `#Item`. However, you may forgo the prefixes if you're referring to tags which were defined in the same module in which they're being used. + +Finally, you may have noticed that, unlike all other data-types, variants re-use some syntax that you're already seen before: _the parentheses_. Clearly, we didn't build our program by creating a bunch of variants, so, what's going on? + +Well, the parenthesis delimit the syntax of what is called a **form** in Lux. This is actually an old concept that's very familiar to those with experience with other Lisp-like languages. Basically, a form is a composite expression or statement. + +When the form starts with a tag, Lux interprets that to be a variant. + +## Types for data-types + +_"But, wait!"_, you might say. _"We didn't talk about functions!"_ + +Patience, young grasshopper. We'll talk about those in the next chapter. + +For now, let's talk about **types**. + +The type-annotation macro is called `:` (I know, _real cute_). You use it like this `(: Some_Type some_value)`. + +There is also a separate macro for type-coerciones that's called `:as`, which is used the same way. However, you should probably steer clear off that one, unless you know what you're doing, since you can trick the compiler into thinking a value belongs to any type you want by using it. + +Now that we know about type annotations, I'll show you some types by giving you some valid Lux expressions: + +``` +(: Bit #1) +(: Bit .true) +(: Nat 123) +(: Int -123) +(: Rev .789) +(: Frac +456.789) +(: Text "YOLO") + +(type: Some_Enum + #primitive + #tuple + #variant) + +(: [Int [Text Some_Enum] Bit] + [10 ["nested" #tuple] .false]) + +(type: Quux + #Foo + (#Bar Int Frac Text)) + +(: Quux #Foo) + +(: Quux (#Bar 10 +20.0 "thirty")) + +(type: Lang + {#name Text + #paradigm Paradigm + #platforms (List Platform)}) + +(: Lang + {#name "Lux" + #paradigm #Functional + #platforms (list #JVM)}) + +(: Lang + ["Lux" #Functional (list #JVM)]) + +(: [Text Paradigm (List Platform)] + {#name "Lux" + #paradigm #Functional + #platforms (list #JVM)}) +``` + + By the way, the value of a type-annotation or a type-coearcion expression is just the value being annotated/coerced. So `(: Bit #1)` simply yields `#1`. + +_What is that `type:` thingie?_ + +It's just a macro for defining types. We'll learn more about it in a future chapter. + +The tags that get mentioned in the type definition get automatically declared, and the order in which they appear determines their value. `#Foo` came first, so it's value is 0. `#Bar`, as you may guess, gets the value 1. + +Also, you might be wondering what's the difference between `List` and `list`. Well, the first one is the type of lists (or a type-constructor for list types, however you want to look at it). The second one is a _macro_ for constructing actual list values. `List` can only take one argument (the type of the list elements), while `list` can take any number of arguments (the elements that make up the list value). + +--- + +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! + |