diff options
author | Eduardo Julian | 2021-09-05 21:03:05 -0400 |
---|---|---|
committer | Eduardo Julian | 2021-09-05 21:03:05 -0400 |
commit | 09e2747bf8c6dcdc1d7318f2490f0de37d77b39f (patch) | |
tree | ccee4dd90b0f5f84d813a8f29b3b9a5dc602068b /documentation | |
parent | 0f7bfa0d4a4e5a79fffe72adec1dd35992c7dde3 (diff) |
Added a chapter on cross-platform Lux.
Diffstat (limited to 'documentation')
25 files changed, 402 insertions, 155 deletions
diff --git a/documentation/book/the_lux_programming_language/appendix_a.md b/documentation/book/the_lux_programming_language/appendix_a.md index 29a84a9df..a14ef2823 100644 --- a/documentation/book/the_lux_programming_language/appendix_a.md +++ b/documentation/book/the_lux_programming_language/appendix_a.md @@ -4,7 +4,7 @@ You've already seen some import syntax, but now you'll see all the options avail If you recall [Chapter 1](chapter_1.md), there was this example code: -``` +```clojure (.module: [library [lux #* @@ -47,7 +47,7 @@ It is also important to note that while imports can be nested for convenience, t The `.module:` declaration could just as easily been written like this: -``` +```clojure (.module: [library/lux #*] [library/lux/program (#+ program:)] @@ -63,7 +63,7 @@ Any module-path fragments included in the import syntax without such options wil It is also possible to have the `.module:` macro open interface implementations for you when importing the modules that contain them. For example: -``` +```clojure (.module: [library [lux #* @@ -89,7 +89,7 @@ The `#` syntax for aliasing can also be used between modules, and not just when For example: -``` +```clojure (.module: [library [lux #* @@ -108,7 +108,7 @@ Non-aliased paths don't count as context. This means: -``` +```clojure (.module: [library [lux #* @@ -128,7 +128,7 @@ I should also note that you can **both** locally import definitions and open imp For example: -``` +```clojure (.module: [library [lux #* @@ -143,7 +143,7 @@ Another important feature of module imports is relative addressing, which comes For the first one, suppose you have the following directory structure: -``` +```clojure program foo bar @@ -160,7 +160,7 @@ And you're writing code in the `program/foo/baz` module. You can import other modules in the hierarchy like this: -``` +```clojure ... In program/foo/baz (.module: [library @@ -183,7 +183,7 @@ You can think about it like this: Also, this relative path syntax can be nested, like so: -``` +```clojure ... In program/foo/baz (.module: [library @@ -199,7 +199,7 @@ Also, this relative path syntax can be nested, like so: Or even: -``` +```clojure ... In program/foo/baz (.module: [library @@ -219,7 +219,7 @@ That is because, since it's nested under another `//`, it's relative to `program For the second way to do relative imports, you can see this example: -``` +```clojure ... In program/foo/baz (.module: [library diff --git a/documentation/book/the_lux_programming_language/appendix_b.md b/documentation/book/the_lux_programming_language/appendix_b.md index 3aaaa7a23..8ff38eb68 100644 --- a/documentation/book/the_lux_programming_language/appendix_b.md +++ b/documentation/book/the_lux_programming_language/appendix_b.md @@ -41,13 +41,13 @@ You see; this might look very impractical to those accustomed to the old way, bu Consider this: -``` +```clojure (|> x (/ scale) (pow 3.0) (- shift)) ``` If I was using the traditional way of doing math, I wouldn't be able to pipe it, and it would look like this: -``` +```clojure (- (pow (/ x scale) 3.0) shift) @@ -67,7 +67,7 @@ It's called `infix`, and it allows you to do infix math, with nested expressions Here's an example: -``` +```clojure (infix [[3.0 pow 2.0] + [5.0 * 8.0]]) ``` diff --git a/documentation/book/the_lux_programming_language/appendix_c.md b/documentation/book/the_lux_programming_language/appendix_c.md index e60f7bbe8..85b976c3c 100644 --- a/documentation/book/the_lux_programming_language/appendix_c.md +++ b/documentation/book/the_lux_programming_language/appendix_c.md @@ -16,7 +16,7 @@ Let's see them in action. ## Pattern-matching macros in the Standard Library -``` +```clojure (case (list 1 2 3) (^ (list x y z)) (#.Some (+ x (* y z))) @@ -29,7 +29,7 @@ You may remember how annoying it was to pattern-match against lists in the [Chap Well, by using the `^` pattern-matching macro, you can use any normal macros you want inside the pattern to profit from their code-construction capacities. -``` +```clojure ... Multi-level pattern matching. ... Useful in situations where the result of a branch depends on further refinements on the values being matched. ... For example: @@ -58,7 +58,7 @@ It's one of those features you don't need often, but when you do, it saves the d The possibilities are endless when it comes to the refinement you can do, and when you consider what you'd have to do to get the same results without it, it's easy to see how much code it saves you. -``` +```clojure ... Allows you to simultaneously bind and de-structure a value. (def: (hash (^@ set [element_hash _])) (list::mix (function (_ elem acc) @@ -69,7 +69,7 @@ The possibilities are endless when it comes to the refinement you can do, and wh `^@` is for when you want to deal with a value both as a whole and in parts. -``` +```clojure ... Same as the "open" macro, but meant to be used as a pattern-matching macro for generating local bindings. ... Can optionally take a "prefix" text for the generated local bindings. (def: #export (range (^open ".") from to) @@ -81,7 +81,7 @@ The possibilities are endless when it comes to the refinement you can do, and wh It's excellent when taking structures as function arguments, or when opening structures locally in `let` expressions. -``` +```clojure ... Or-patterns. (type: Weekday #Monday @@ -106,7 +106,7 @@ It's excellent when taking structures as function arguments, or when opening str It's a real time-saver. -``` +```clojure ... It's similar to do-template, but meant to be used during pattern-matching. (def: (beta_reduce env type) (-> (List Type) Type Type) @@ -151,7 +151,7 @@ You can save yourself quite a lot of typing (and debugging) by reusing a lot of It's a great asset! -``` +```clojure ... Allows you to extract record members as local variables with the same names. ... For example: (let [(^slots [#foo #bar #baz]) quux] @@ -162,7 +162,7 @@ It's a great asset! Now you can work with record member values with ease. -``` +```clojure ... Allows destructuring of streams in pattern-matching expressions. ... Caveat emptor: Only use it for destructuring, and not for testing values within the streams. (let [(^sequence& x y z _tail) (some_sequence_function 1 2 3)] @@ -213,7 +213,7 @@ However, most of the time, you'll just return the branches (and sometimes the bo To make things easier to understand, here is the implementation of the `^` macro, from the `library/lux` module: -``` +```clojure (macro: (^ tokens) (case tokens (#Item [_ (#Form (#Item pattern #End))] (#Item body branches)) diff --git a/documentation/book/the_lux_programming_language/appendix_d.md b/documentation/book/the_lux_programming_language/appendix_d.md index 5935ac5c3..16d49b6bb 100644 --- a/documentation/book/the_lux_programming_language/appendix_d.md +++ b/documentation/book/the_lux_programming_language/appendix_d.md @@ -20,7 +20,7 @@ I added the `library/lux/control/pipe` module, which contains several macros mea Take a look at these babies: -``` +```clojure ... Loops for pipes. ... Both the testing and calculating steps are pipes and must be given inside tuples. (|> 1 @@ -38,7 +38,7 @@ Which value? Whatever has been piped into `loop>` from the underlying `|>` (in t --- -``` +```clojure ... Branching for pipes. ... Both the tests and the bodies are piped-code, and must be given inside a tuple. ... If a last else-pipe isn't given, the piped-argument will be used instead. @@ -55,7 +55,7 @@ But what's that thing over there? That `new>` thing? Well, it's another piping macro. Of course! -``` +```clojure ... Ignores the piped argument, and begins a new pipe. (|> 20 (i.* 3) @@ -69,7 +69,7 @@ Useful in certain kinds of situations. --- -``` +```clojure ... Gives a name to the piped-argument, within the given expression. (|> 5 (let> @ (+ @ @))) @@ -81,7 +81,7 @@ Pretty nifty, huh? --- -``` +```clojure ... Pattern-matching for pipes. ... The bodies of each branch are NOT pipes; just regular values. (|> 5 @@ -106,7 +106,7 @@ You'll thank me later. --- -``` +```clojure ... Monadic pipes. ... Each steps in the monadic computation is a pipe and must be given inside a tuple. (|> 5 @@ -128,7 +128,7 @@ All you need is a macro that takes anything you want as parameters, but always t As an example, here's the definition for `let>`: -``` +```clojure (syntax: .public (let> [binding <code>.any body <code>.any prev <code>.any]) @@ -148,7 +148,7 @@ Oh... and did I mention the `|>>` macro? It generates for you a single-argument function that will immediately pipe its argument through all the steps you give it? -``` +```clojure (only (|>> (member? forbidden-definitions) not) all_definitions) diff --git a/documentation/book/the_lux_programming_language/appendix_e.md b/documentation/book/the_lux_programming_language/appendix_e.md index b7740abf2..a68636e91 100644 --- a/documentation/book/the_lux_programming_language/appendix_e.md +++ b/documentation/book/the_lux_programming_language/appendix_e.md @@ -83,7 +83,7 @@ One that I really like and has turned out to be very useful to me, is that you c Here are some examples from the `library/lux/ffi` module, where I have some types and code-parsers for the many macros implemented there: -``` +```clojure (type: .public Privacy (Variant #PublicP @@ -113,7 +113,7 @@ This wouldn't be possible if variant types weren't nested/composable; forcing me Here's an example of `<>.and` in action: -``` +```clojure ... From library/lux/target/jvm/type (type: .public Argument [Text (Type Value)]) diff --git a/documentation/book/the_lux_programming_language/appendix_f.md b/documentation/book/the_lux_programming_language/appendix_f.md index b977623a8..461d54417 100644 --- a/documentation/book/the_lux_programming_language/appendix_f.md +++ b/documentation/book/the_lux_programming_language/appendix_f.md @@ -37,14 +37,14 @@ Fantastic! This is how you'd use it: -``` +```clojure ... Equality for nats (\ nat.equivalence = x y) ## vs (\\ = x y) ``` -``` +```clojure ... Equality for lists of nats (\ (list.equivalence nat.equivalence) = (list.indices 10) @@ -53,7 +53,7 @@ This is how you'd use it: (\\ = (list.indices 10) (list.indices 10)) ``` -``` +```clojure ... Functor mapping (\ list.functor each nat.inc (list.indices 10)) ... vs diff --git a/documentation/book/the_lux_programming_language/appendix_g.md b/documentation/book/the_lux_programming_language/appendix_g.md index 49f8e92db..9d6505c77 100644 --- a/documentation/book/the_lux_programming_language/appendix_g.md +++ b/documentation/book/the_lux_programming_language/appendix_g.md @@ -10,7 +10,7 @@ Of course, the parser may fail, in which case the user should receive some meani The `library/lux/control/parser/text` library provides a type, and a host of combinators, for building and working with text parsers. -``` +```clojure (type: .public Offset Nat) @@ -37,7 +37,7 @@ The `regex` macro, in turn, compiles the given syntax into a text parser, which Here are some samples for regular expressions: -``` +```clojure ... Literals (regex "a") @@ -119,7 +119,7 @@ This is important because the groups and alternations that you use in your regul For example: -``` +```clojure ... This returns a single piece of text (regex "a{1,}") diff --git a/documentation/book/the_lux_programming_language/appendix_h.md b/documentation/book/the_lux_programming_language/appendix_h.md index e766963c6..b20a6240f 100644 --- a/documentation/book/the_lux_programming_language/appendix_h.md +++ b/documentation/book/the_lux_programming_language/appendix_h.md @@ -119,7 +119,7 @@ This allows you to segregate useful configuration into different profiles and th Now that we have seen the available commands, it would be useful to see an annotated example `project.lux` file to see what bits of configuration it can contain. -``` +```clojure ["" ... The empty text ("") is used to specify the default profile. [... An optional identity for the project. ... It can also be specified or overriden in a non-default profile. diff --git a/documentation/book/the_lux_programming_language/chapter_1.md b/documentation/book/the_lux_programming_language/chapter_1.md index bb9156cfa..0b93b5f29 100644 --- a/documentation/book/the_lux_programming_language/chapter_1.md +++ b/documentation/book/the_lux_programming_language/chapter_1.md @@ -34,7 +34,7 @@ These are the steps: 2. Create a new project file at `my_project/project.lux`. 3. Add this to the project file: -``` +```clojure {#identity ["my.group" "my_project" "0.1.0-SNAPSHOT"] #repositories ["https://oss.sonatype.org/content/repositories/snapshots/" "https://oss.sonatype.org/service/local/staging/deploy/maven2/"] @@ -51,7 +51,7 @@ These are the steps: 4. Create `my_project/source/main.lux` and add this code to it: -``` +```clojure (.module: [library [lux #* diff --git a/documentation/book/the_lux_programming_language/chapter_10.md b/documentation/book/the_lux_programming_language/chapter_10.md index cb7e3f583..9d136bc2e 100644 --- a/documentation/book/the_lux_programming_language/chapter_10.md +++ b/documentation/book/the_lux_programming_language/chapter_10.md @@ -48,7 +48,7 @@ But macros work with the Lux _AST_, so that's the first thing you need to master Check it out: -``` +```clojure (type: #export Location {#module Text #line Nat @@ -104,7 +104,7 @@ Imagine having to generate an entire function definition (or something even larg Well, don't fret. The Lux Standard Library already comes with a powerful mechanism for easily generating any code you want and you don't even need to import it (i.e. it's in the `library/lux` module). -``` +```clojure ... Quotation as a macro. (' "YOLO") ``` @@ -118,7 +118,7 @@ If you want to know what that would look like with the tools at `library/lux/mac The beautiful thing is that `(' (you can use the "'" #macro [to generate {arbitrary code} without] worrying (about the "complexity")))`. -``` +```clojure ... Hygienic quasi-quotation as a macro. ... Unquote (~) and unquote-splice (~+) must also be used as forms. ... All unprefixed identifiers will receive their parent module's prefix if imported; otherwise will receive the prefix of the module on which the quasi-quote is being used. @@ -143,7 +143,7 @@ With these tools, you can introduce a lot of complexity and customization into y This ensures that if you make a mistake writing your template code, it will be easy to spot during development. Also, it will be harder to collide (by mistake) with user code if you, for instance, write the code for making a local variable named `foo`, and then the person using your macro uses a different `foo` somewhere in their code. -``` +```clojure ... Unhygienic quasi-quotation as a macro. ... Unquote (~) and unquote-splice (~+) must also be used as forms. (`' (def: (~ name) @@ -161,7 +161,7 @@ Now that you know how to generate code like a pro, it's time to see how macros g First, let's check the type of macros: -``` +```clojure (type: .public Macro (primitive "#Macro")) ``` @@ -177,7 +177,7 @@ It does so by labelling (_type-wise_) with this funky type. There is, however, another type which elucidates what is going on with macros. -``` +```clojure (type: .public Macro' (-> (List Code) (Meta (List Code)))) ``` @@ -187,7 +187,7 @@ Now, you can see how everything connects. You define macros by using the `macro:` macro (_so meta..._): -``` +```clojure (macro: .public (name_of tokens) {#.doc (doc "Given an identifier or a tag, gives back a 2 tuple with the module and name parts, both as Text." (name_of #.doc) @@ -205,7 +205,7 @@ You define macros by using the `macro:` macro (_so meta..._): Here's another example: -``` +```clojure (macro: .public (else tokens state) {#.doc (doc "Allows you to provide a default value that will be used" "if a (Maybe x) value turns out to be #.None." diff --git a/documentation/book/the_lux_programming_language/chapter_11.md b/documentation/book/the_lux_programming_language/chapter_11.md index ad4366a76..a2d603ca0 100644 --- a/documentation/book/the_lux_programming_language/chapter_11.md +++ b/documentation/book/the_lux_programming_language/chapter_11.md @@ -16,7 +16,7 @@ The `library/lux/control/parser/code` module houses some powerful tools. For starters, it's the home of the (_code_) `Parser` type: -``` +```clojure (type: .public Parser {#.doc "A Lux code parser."} (//.Parser (List Code))) @@ -24,7 +24,7 @@ For starters, it's the home of the (_code_) `Parser` type: Which is based on the `Parser` type from the `library/lux/control/parser` module: -``` +```clojure (type: .public (Parser s a) {#.doc "A generic parser."} (-> s (Try [s a]))) @@ -40,7 +40,7 @@ There are many such code-parsers (and combinators) in the `library/lux/control/p Then, in the `library/lux/macro/syntax` module, there is a mechanism for defining macros: the `syntax:` macro. -``` +```clojure "A more advanced way to define macros than 'macro:'." "The inputs to the macro can be parsed in complex ways through the use of syntax parsers." "The macro body is also (implicitly) run in the Meta monad, to save some typing." @@ -73,7 +73,7 @@ What do those code-parsers look like? Here is an example: -``` +```clojure ... Taken from library/lux/math/infix. (.module: @@ -150,7 +150,7 @@ Here is an example: And here are some examples of syntax macros: -``` +```clojure ... Also from library/lux/math/infix. (def: (prefix infix) @@ -184,7 +184,7 @@ And here are some examples of syntax macros: (in (list (..prefix expr)))) ``` -``` +```clojure (syntax: .public (^sequence& {patterns (<code>.form (<>.many <code>.any))} body {branches (<>.some <code>.any)}) @@ -201,7 +201,7 @@ And here are some examples of syntax macros: (in (list& g!sequence body+ branches))))) ``` -``` +```clojure (syntax: .public (cond> {_ _reversed_} prev {else body^} diff --git a/documentation/book/the_lux_programming_language/chapter_12.md b/documentation/book/the_lux_programming_language/chapter_12.md index 8e4c0b8c0..94e072823 100644 --- a/documentation/book/the_lux_programming_language/chapter_12.md +++ b/documentation/book/the_lux_programming_language/chapter_12.md @@ -62,7 +62,7 @@ Well, by using types; of course! If you head to the `library/lux/control/io` module, you will find the following type definition: -``` +```clojure (abstract: .public (IO a) ... ) diff --git a/documentation/book/the_lux_programming_language/chapter_13.md b/documentation/book/the_lux_programming_language/chapter_13.md index afd08f5fd..1faba95ee 100644 --- a/documentation/book/the_lux_programming_language/chapter_13.md +++ b/documentation/book/the_lux_programming_language/chapter_13.md @@ -28,7 +28,7 @@ Let's explore them. It's all done with the help of the `import:` macro: -``` +```clojure ... Allows importing JVM classes, and using them as types. ... Their methods, fields and enum options can also be imported. (import: java/lang/Object @@ -96,7 +96,7 @@ As you have noticed, it works by creating functions (and constant values) for al Normally, you'd use the `class:` macro: -``` +```clojure ... Allows defining JVM classes in Lux code. ... For example: (class: #final (TestClass A) [Runnable] @@ -131,7 +131,7 @@ Normally, you'd use the `class:` macro: And, for anonymous classes, you'd use `object`: -``` +```clojure ... Allows defining anonymous classes. ... The 1st tuple corresponds to class-level type-variables. ... The 2nd tuple corresponds to parent interfaces. @@ -149,14 +149,14 @@ And, for anonymous classes, you'd use `object`: * Accessing class objects. -``` +```clojure ... Loads the class as a java.lang.Class object. (class_for java/lang/String) ``` * Test instances. -``` +```clojure ... Checks whether an object is an instance of a particular class. ... Caveat emptor: Can't check for polymorphism, so avoid using parameterized classes. (case (check java/lang/String "YOLO") @@ -166,7 +166,7 @@ And, for anonymous classes, you'd use `object`: * Synchronizing threads. -``` +```clojure ... Evaluates body, while holding a lock on a given object. (synchronized object-to-be-locked (exec @@ -177,7 +177,7 @@ And, for anonymous classes, you'd use `object`: Calling multiple methods consecutively -``` +```clojure ... Call a variety of methods on an object. Then, return the object. (do_to object (ClassName::method1 arg0 arg1 arg2) diff --git a/documentation/book/the_lux_programming_language/chapter_14.md b/documentation/book/the_lux_programming_language/chapter_14.md index e0a0fc638..8b3fc49d9 100644 --- a/documentation/book/the_lux_programming_language/chapter_14.md +++ b/documentation/book/the_lux_programming_language/chapter_14.md @@ -50,7 +50,7 @@ The result is that, through the `do` macro, you can implement complex concurrent If you're curious about how that looks, take a peek: -``` +```clojure (def: .public (and left right) (All [a b] (-> (Async a) (Async b) (Async [a b]))) (do monad @@ -112,7 +112,7 @@ Also, interaction with actors is based on _message-passing_, and an actor may co The relevant module is the `library/lux/control/concurrency/actor` module, and the relevant type is: -``` +```clojure (abstract: .public (Actor s) ... ) @@ -128,7 +128,7 @@ Just from this definition, it's easy to see that actors are stateful (a necessit To create an actor, you must first specify its `Behavior`: -``` +```clojure (type: .public (Behavior o s) {#on_init (-> o s) #on_mail (-> (Mail s) s (Actor s) (Async (Try s)))}) @@ -140,7 +140,7 @@ You can then call the `spawn!` function with an initial state and a `Behavior`. But writing complex actors with multiple options for its messages can be messy with these tools, so a macro was made to simplify that. -``` +```clojure ... Defines a named actor, with its behavior and internal state. ... Messages for the actor must be defined after the on_mail handler. (actor: .public (stack a) diff --git a/documentation/book/the_lux_programming_language/chapter_16.md b/documentation/book/the_lux_programming_language/chapter_16.md index 929188f35..0040876d0 100644 --- a/documentation/book/the_lux_programming_language/chapter_16.md +++ b/documentation/book/the_lux_programming_language/chapter_16.md @@ -19,7 +19,7 @@ Not only that, but the _Aedifex_ build tool for Lux also includes a command for How do you set that up? Let's take a look at the `project.lux` file for the Lux standard library itself. -``` +```clojure {#identity ["com.github.luxlang" "stdlib" "0.6.0"] #deploy_repositories {"snapshots" "https://oss.sonatype.org/content/repositories/snapshots/" @@ -37,7 +37,7 @@ The `#test` parameter is similar to the `#program` parameter in that it specifie Here is a summary of the file: -``` +```clojure (.module: [library ["/" lux #* @@ -69,7 +69,7 @@ To know how tests work, let's take a look at one of those modules. From `test/lux/data/collection/stack`. -``` +```clojure (.module: [library [lux #* @@ -168,5 +168,9 @@ Without tests, the reliability of programs becomes a matter of faith, not engine Automated tests can be integrated into processes of continuous delivery and integration to increase the confidence of individuals and teams that real value is being delivered, and that the customer won't be dissatisfied by buggy software. -Now that you know how to test your programs, you know everything you need to know to be a Lux programmer. +Now that you know how to test your programs, you know everything you need to know to be a Lux programmer... on the JVM. + +However, Lux has been expanded with support for other platforms, and it's time for you to learn about some of its capabilities. + +See you in [the next chapter](chapter_17.md)! diff --git a/documentation/book/the_lux_programming_language/chapter_17.md b/documentation/book/the_lux_programming_language/chapter_17.md new file mode 100644 index 000000000..b75df3cb2 --- /dev/null +++ b/documentation/book/the_lux_programming_language/chapter_17.md @@ -0,0 +1,241 @@ +# Chapter 17: Cross-platform Lux + +_Where you will sail to exotic foreign platforms on the S.S. Lux._ + +It was always my desire for Lux to be a language that could be used to write software in multiple platforms. + +I've always found it annoying to write a piece of software on one language, and then if it became necessary to run the software under different circumstances, a rewrite had to be done because the language in which the software was written was not capable of adapting to the new requirements. + +In theory, programming languages are universal. +Logic is logic, no matter the language in which it is expressed. +Instructions are instructions, no matter who executes them. + +And yet, in practice, you need JavaScript for the browser, and Swift for the IPhone (to give you some examples). + +Granted, with the advent of WebAssembly, it has now become possible to have any options you want for the browser, instead of being locked to JavaScript and any languages that transpile to it. + +But there is still another type of constraint that is probably not going away any time soon. + +If a programmer or a company write a piece of software on some language, they have made a very significant investment. +If tomorrow, they realize that another language might be a better fit for what they need, it might be too costly for them to rewrite their software on the new language. + +Cross-platform support for Lux is not just about accessing as many devices as possible, but also about being able to inter-operate with as many languages as possible. +Being able to interact with and extend a Python server, or a Lua script. + +Ideally, I would like Lux to be able to inter-operate with every programming language that exists, thereby giving Lux programmers the capacity to write any program they want for any device; and the capacity to extend any codebase without being forcefully tied to any legacy language or implementation. + +Sadly, the ideal world can only exist within our dreams, but (as of v0.6) steps have been taken to bring the dream closer to reality. + +Currently, it is possible to write Lux programs that compile to the following target platforms: + +* Java Virtual Machines +* JavaScript interpreters (such as browsers, and Node JS) +* Python interpreters +* Lua interpreters +* Ruby interpreters + +Not only is that possible, but great care has been taken to make sure Lux works consistently across each of those platforms. + +That means 2 things: + +1. If your Lux program behaves one way in one platform, you can expect it to behave the same way in any other, _minus performance considerations_. +1. There is only one language for programming in any of those platforms: Lux. There is no _LuxScript_ or _PyLux_. Lux is a **single** programming language, not a family of languages. + +The 2nd point is important, because another possible design could have been to have slightly different variations of Lux as different programming languages (albeit, sharing most of their syntax and semantics), each one targeting one of those platforms. + +This could have been a very nice approach, as each of those platforms works slightly differently, so it's not crazy to think that each variation of Lux could adapt itself to those differences to offer a programmign experience closer to the platform. + +The problem with this approach is that libraries written for one platform might not work for the others (or work _correctly_) because they would make certain assumptions about how things work that would be true for their platform of origin, but not in general. + +This approach would allow Lux programmers to target different platforms, but it would make sharing code between them impossible at worst, and risky at best. + +Instead, I've designed the semantics and the feature set of Lux to be independent of any host platform. +When the feature-set of a platform fits well with the feature-set of Lux, I use the platform's resources to implement Lux's functionality. +And when Lux needs something the platform does not offer, but does not disallow either, I emulate the feature in other to ensure a consistent experience. + +This means all of Lux's integers and naturals are 64-bit, on the JVM (which supports them), and even on JavaScript (where they are emulated). +And this also means that Lux's concurrency mechanisms work as expected on the JVM (which allows multi-core processing), and on JavaScript/Python/Lua/Ruby (which don't). + +--- + +In order to compile a Lux program to any of these alternative platforms, you must use a different compiler for each. + +An Aedifex `project.lux` file allows for a `"compiler"` option to specify (as a dependency) the compiler you wish to use. + +This option can be omitted, in which case it will pick, as a default value: `["com.github.luxlang" "lux-jvm" "0.6.0" "jar"]`. + +Here are the compilers for the alternative platforms: + +* For JavaScript: `["com.github.luxlang" "lux-js" "0.6.0" "js"]` +* For Python: `["com.github.luxlang" "lux-python" "0.6.0" "jar"]` +* For Lua: `["com.github.luxlang" "lux-lua" "0.6.0" "jar"]` +* For Ruby: `["com.github.luxlang" "lux-ruby" "0.6.0" "jar"]` + +You don't need to use any special command on Aedifex in order to compile Lux to any alternative platform. +Just set the compiler, and build/test your program as usual. + + For a thorough specification of what Aedifex can do, please refer to [Appendix H](appendix_h.md). + +In the same way that the JVM compiler produces a _single_ executable JAR file, each of these compilers will produce a _single_ executable `.js`/`.py`/`.lua`/`.rb` file that can directly be executed with the usual interpreters for those languages. + +--- + +You might be wondering, though, how is it possible to share Lux code that is meant to work on these different platforms, given that they have different features, and different libraries. + +_How is it possible to write Lux code that works everywhere, instead of being tied to the minutiae of each platform?_ + +Lux offers 2 different mechanisms to write cross-platform code. + +One of them is meant to be used when most of the code you're writing is the same regardless of platform, and you just need to add some snippets here and there to access some specific things in each platform. + +And the other is meant for when the changes are so massive, you might as well just write different files for different platforms. + +First, let's go with the smaller mechanism: + +```clojure +(def: js "JavaScript") + +(for {"JVM" (do jvm stuff) + ..js (do js stuff)} + (do default stuff)) +``` + +The `for` macro allows you to specify the code to use for each platform. + +Each Lux compiler has a name (as a `Text`) for the platform it compiles to, and this information is made available to macros through the state of the compiler. + +The `for` macro just compares this name to whatever options you give it in order to select what code to use when compiling to a given platform. + +Additionally, it is possible to provide an (_optional_) snippet of code, to use in case there isn't a more specific snippet available. + +Also, as you can see, the names for the platforms don't need to be provided as `Text` literals, as `for` knows how to resolve the names of definitions to get the options that way. + +This is specially useful to avoid typos causing trouble when using `for`. + +The module `library/lux/target` contains constants with the names of currently supported platforms, so it's a good idea to rely on that instead of manually specifying the names. + + If you check out `library/lux/target`, you might notice that there are more constants than there are currently supported platforms. + This is because I made the effort to add additional platforms to Lux, but due to complications, I had to postpone them for later. + The constants were left there anyway, since there is some code that depends on them on some of the more platform-specific parts of the standard library. + As I finish the remaining back-ends, these constants will gain relevance again. + +To give you an example of `for` in action, here is a definition from the `library/lux/data/text` module: + +```clojure +(def: .public (replaced pattern replacement template) + (-> Text Text Text Text) + (for {@.old + (:as Text + ("jvm invokevirtual:java.lang.String:replace:java.lang.CharSequence,java.lang.CharSequence" + (:as (primitive "java.lang.String") template) + (:as (primitive "java.lang.CharSequence") pattern) + (:as (primitive "java.lang.CharSequence") replacement))) + @.jvm + (:as Text + ("jvm member invoke virtual" [] "java.lang.String" "replace" [] + (:as (primitive "java.lang.String") template) + ["Ljava/lang/CharSequence;" (:as (primitive "java.lang.CharSequence") pattern)] + ["Ljava/lang/CharSequence;" (:as (primitive "java.lang.CharSequence") replacement)])) + ... TODO: Comment/turn-off when generating a JS compiler using a JVM-based compiler because Nashorn's implementation of "replaceAll" is incorrect. + @.js + (:as Text + ("js object do" "replaceAll" template [pattern replacement])) + @.python + (:as Text + ("python object do" "replace" template pattern replacement)) + ... TODO @.lua + @.ruby + (:as Text + ("ruby object do" "gsub" template pattern replacement)) + @.php + (:as Text + ("php apply" (:expected ("php constant" "str_replace")) + pattern replacement template)) + ... TODO @.scheme + ... TODO @.common_lisp + ... TODO @.r + } + ... Inefficient default + (loop [left "" + right template] + (case (..split_by pattern right) + (#.Some [pre post]) + (recur ($_ "lux text concat" left pre replacement) post) + + #.None + ("lux text concat" left right))))) +``` + +This function implements text-replacement in a _generic_ way, while also taking advantage of platform-specific functionality where available. + +--- + +The 2nd mechanism for writing cross-platform code is to specify platform-specific Lux files. + +The way this works is by adding a secondary extension to your Lux files. + +A normal Lux file looks like this: `foo.lux`. + +When a Lux compiler sees that, it assumes the file contains code which is expected to work on any platform Lux can compile to. + +However, it is possible to specify that a file contains code that is only meant for a specific platform, like this: + +* For the JVM: `foo.jvm.lux` +* For JavaScript: `foo.js.lux` +* For Python: `foo.py.lux` +* For Lua: `foo.lua.lux` +* For Ruby: `foo.rb.lux` + +If you're using, let's say, the JavaScript compiler for Lux (i.e. `["com.github.luxlang" "lux-js" "0.6.0" "js"]`), whenever you import a module as a dependency, the compiler will first look for a file with the `.js.lux` extension, and if it fails to find one, it will look for a file with the plain `.lux` extension. + +_What happens if I do not have a `.js.lux` file, but I do have files with the other special extensions?_ + +A Lux compiler will always ignore files with extensions for platforms other than its own. + +It will only ever take into account its own custom extension, and the general extension, so you don't need to worry about the wrong code being compiled. + +A good example of this mechanism in action is the `library/lux/ffi` module. + +This module provides several macros for making host-platform interoperation very easy to do. + +Since the whole point of `library/lux/ffi` is platform interoperation, there is no point in there ever being a generic `library/lux/ffi.lux` file. + +Instead, there is a `library/lux/ffi.jvm.lux` file, a `library/lux/ffi.js.lux` file, a `library/lux/ffi.py.lux` file, a `library/lux/ffi.lua.lux` file, and a `library/lux/ffi.rb.lux` file. + +It makes the most sense to provide this module as a set of platform-specific files, instead of a single file that uses `for`, because everything in those files is platform-specific and there can be no meaningful re-use, so a version of that module which is a single file using `for`, would be an incomprehensible monstrosity. + +But, by splitting the code into platform specific files, everything can be kept nice and tidy. + + You might also want to take a close look at the documentation for `library/lux/ffi` to see what macros are available. + I wouldn't be surprised if you looked at the previous example of the `replaced` function and thought: _YUCK!_. + Don't worry about it. Such ugly code is un-characteristic of _the Lux experience_. + The reason why that code looks that way is because the `library/lux/data/text` gets implemented before `library/lux/ffi`, and so it cannot use any of the machinery specified therein. + _Your code_ will have access to `library/lux/ffi`, so you can write much nicer code that doesn't have to concern itself with the low-level nitty-gritty details. + +--- + +You might be puzzled by what you saw in that `replaced` example. + +_You're calling text as if it was a function?_ + +Not quite. + +You see, not all functionality a programming language provides can be implemented entirely within the programming language. + +Sometimes, there are primitive bits of functionality that have to be baked into the language from the get-go. + +Lux's mechanism for exposing those bits is as _extensions_ to the compiler. + +Some of these extensions are _common_ to each compiler, and can be expected to be around regardless of whether you're compiling to the JVM, to JavaScript, or anywhere else. + +Other extensions are _host_-specific, and are only meant to be around for a specific platform. + +Either way, Lux uses the same mechanism for all of them: the humble _extension_. + +You want to know what's the coolest thing about extensions? +_**You can write your own**_, and by doing so you can teach the compiler how to type-check, optimize and even generate code for your own new types of expressions. + +Sounds cool? + +See you in [the next chapter](chapter_18.md)! + diff --git a/documentation/book/the_lux_programming_language/chapter_2.md b/documentation/book/the_lux_programming_language/chapter_2.md index a58e7758f..0bd29faf3 100644 --- a/documentation/book/the_lux_programming_language/chapter_2.md +++ b/documentation/book/the_lux_programming_language/chapter_2.md @@ -59,7 +59,7 @@ We'll also explore macros further in later chapters. ## Comments -``` +```clojure ## They look like this. ## They all start with 2 continuous # characters and go on until the end of the line. ``` @@ -108,7 +108,7 @@ Now, let's talk a bit more about the program we saw last time. In the previous chapter we compiled and ran a Lux program, but nothing has been explained yet. Let's review the code and see in detail what was done. -``` +```clojure (.module: {#.doc "This will be our program's main module."} [library diff --git a/documentation/book/the_lux_programming_language/chapter_3.md b/documentation/book/the_lux_programming_language/chapter_3.md index a8e3c3247..a08fbc618 100644 --- a/documentation/book/the_lux_programming_language/chapter_3.md +++ b/documentation/book/the_lux_programming_language/chapter_3.md @@ -8,14 +8,14 @@ _Where you will learn the what Lux code is made of._ * `Bit`s look like this: -``` +```clojure #0 ## false #1 ## true ``` * `Nat`s look like this: -``` +```clojure 0 123 0456 @@ -24,7 +24,7 @@ _Where you will learn the what Lux code is made of._ * `Int`s look like this: -``` +```clojure +0 -123 +0456 @@ -33,7 +33,7 @@ _Where you will learn the what Lux code is made of._ * `Rev`s look like this: -``` +```clojure .123 .04,56 .7890 @@ -41,7 +41,7 @@ _Where you will learn the what Lux code is made of._ * `Frac`s look like this: -``` +```clojure +123.456 -456.7890 +0.001 @@ -50,32 +50,32 @@ _Where you will learn the what Lux code is made of._ * `Text`s look like this: -``` +```clojure "This is a single-line text" ``` * `Unit` looks like this: -``` +```clojure [] ``` * Variants look like this: -``` +```clojure #Foo (#Bar 10 +20.0 "thirty") ``` * Tuples look like this: -``` +```clojure [123 ["nested" #tuple] true] ``` * Records look like this: -``` +```clojure {#name "Lux" #paradigm #Functional #platforms (list #JVM)} ``` @@ -161,7 +161,7 @@ There is also a separate macro for type-coerciones that's called `:as`, which is Now that we know about type annotations, I'll show you some types by giving you some valid Lux expressions: -``` +```clojure (: Bit #1) (: Bit .true) (: Nat 123) diff --git a/documentation/book/the_lux_programming_language/chapter_4.md b/documentation/book/the_lux_programming_language/chapter_4.md index 68feb8121..8387715c6 100644 --- a/documentation/book/the_lux_programming_language/chapter_4.md +++ b/documentation/book/the_lux_programming_language/chapter_4.md @@ -10,7 +10,7 @@ No worries. You're about to find out! First, let's talk about how to make your own functions. -``` +```clojure (function (plus_two x) (inc (inc x))) ``` @@ -21,7 +21,7 @@ What is it's type? Well, I'm glad you asked. -``` +```clojure (: (-> Nat Nat) (function (plus_two x) (inc (inc x)))) ``` @@ -29,7 +29,7 @@ Well, I'm glad you asked. That `->` thingie you see there is a macro for generating function types. It works like this: -``` +```clojure (-> arg1 arg2 ... argN return) ``` @@ -37,7 +37,7 @@ The types of the arguments and the return type can be any type you want (even ot How do we use our function? Just put it at the beginning for a form: -``` +```clojure ((function (plus_two x) (inc (inc x))) 5) ## => 7 ``` @@ -50,7 +50,7 @@ How do we use the `plus_two` function without having to inline its definition (l Well, we just need to define it! -``` +```clojure (def: plus_two (: (-> Nat Nat) (function (_ x) @@ -59,7 +59,7 @@ Well, we just need to define it! Or, alternatively: -``` +```clojure (def: plus_two (-> Nat Nat) (function (_ x) @@ -70,7 +70,7 @@ Notice how the `def:` macro can take the type of its value before the value itse Now, we can use the square function more conveniently. -``` +```clojure (plus_two 7) ## => 9 ``` @@ -79,7 +79,7 @@ Nice! Also, I forgot to mention another form of the `def:` macro which is even more convenient: -``` +```clojure (def: (plus_two x) (-> Nat Nat) (inc (inc x))) @@ -99,7 +99,7 @@ Functions, of course, can take more than one argument, and you can even refer to Check this one out: -``` +```clojure (def: (factorial' acc n) (-> Nat Nat Nat) (if (n.= 0 n) @@ -113,7 +113,7 @@ Check this one out: And if we just had the function expression itself, it would look like this: -``` +```clojure (function (factorial' acc n) (if (n.= 0 n) acc @@ -132,7 +132,7 @@ The reason it exists is that Lux's arithmetic functions are not polymorphic on t If you import the module for `Nat` numbers, like so: -``` +```clojure (.module [library [lux @@ -149,7 +149,7 @@ Also, it might be good to explain that Lux functions can be partially applied. T That means, our factorial function could have been implemented like this: -``` +```clojure (def: factorial (-> Nat Nat) (factorial' +1)) @@ -157,7 +157,7 @@ That means, our factorial function could have been implemented like this: Or, to make it shorter: -``` +```clojure (def: factorial (factorial' +1)) ``` diff --git a/documentation/book/the_lux_programming_language/chapter_5.md b/documentation/book/the_lux_programming_language/chapter_5.md index 0d8b6e976..a391f99f2 100644 --- a/documentation/book/the_lux_programming_language/chapter_5.md +++ b/documentation/book/the_lux_programming_language/chapter_5.md @@ -18,7 +18,7 @@ But before we head into that, let's first see 2 weaker mechanisms for branching We've already met the humble `if` expression in the previous chapter. As explained there, the expression takes the following form: -``` +```clojure (if test then else) @@ -28,7 +28,7 @@ Where `test`, `then` and `else` are arbitrary Lux expressions. In terms of types, it works like this: -``` +```clojure (: X (if (: Bit test) (: X then) (: X else))) @@ -36,7 +36,7 @@ In terms of types, it works like this: Here is an example: -``` +```clojure (if true "Oh, yeah!" "Aw, hell naw!") @@ -52,7 +52,7 @@ For those of you coming from conventional programming languages, `cond` is like It looks like this: -``` +```clojure (cond test-1 then-1 test-2 then-2 ... @@ -62,7 +62,7 @@ It looks like this: And, in terms of types, it looks like this: -``` +```clojure (: X (cond (: Bit test-1) (: X then-1) (: Bit test-2) (: X then-2) ... @@ -73,7 +73,7 @@ And, in terms of types, it looks like this: Here is an example: -``` +```clojure (cond (n.even? num) "even" (n.odd? num) "odd" ## else-branch @@ -98,7 +98,7 @@ We can see its power by looking at some examples. For instance, the `factorial'` function you saw in the previous chapter could have been written like this: -``` +```clojure (def: (factorial' acc n) (-> Nat Nat Nat) (case n @@ -115,7 +115,7 @@ The _"default"_ branch works because we're binding the value of `n` onto a varia However, since it is binding a variable, that means we could have used `_` instead of `n` during our calculations; like this: -``` +```clojure (def: (factorial' acc n) (-> Nat Nat Nat) (case n @@ -134,7 +134,7 @@ Regarding the _"much more"_ claim, you should check out [Appendix C](appendix_c. Here are a couple more examples so you can see the possibilities. -``` +```clojure (let [test true] (case test #1 "Oh, yeah!" @@ -142,7 +142,7 @@ Here are a couple more examples so you can see the possibilities. )) ``` -``` +```clojure (case (list 1 2 3) (#.Item x (#.Item y (#.Item z #.End))) (#.Some (n.+ x (n.* y z))) @@ -156,7 +156,7 @@ In the first example, you'll notice that we have rewritten the prior `if` exampl `let` is a simple way to create local-variables in Lux. It's syntax looks like this: -``` +```clojure (: X (let [var-1 expr-1 var-2 expr-2 ... @@ -174,7 +174,7 @@ Now, in the second example, we're deconstructing a list in order to extract its The `List` type is defined like this: -``` +```clojure (type: (List a) #End (#Item a (List a))) @@ -204,7 +204,7 @@ In functional programming, _recursion_ is the main mechanism for looping in your Recursion is nothing more than the capacity for a function to call itself (often with different parameters than the initial call). It's not hard to see how this mechanism can be used to loop in any way you want, and we've already seen examples of recursion in action. -``` +```clojure (def: (factorial' acc n) (-> Nat Nat Nat) (if (n.= 0 n) @@ -224,7 +224,7 @@ Our example `factorial'` function has its recursive call in the _tail position_ This alternative doesn't: -``` +```clojure (def: (factorial' acc n) (-> Nat Nat Nat) (if (n.= 0 n) @@ -252,7 +252,7 @@ Lux also offers a macro that gives you a slightly similar experience to those ki To see it in action, let's rewrite (once more!) our `factorial` function: -``` +```clojure (def: (factorial n) (-> Nat Nat) (loop [acc 1 @@ -274,7 +274,7 @@ It's based on using a single macro, called `|>`, which allows you to write deepl Here is a simple example to see how it works: -``` +```clojure (|> elems (map to_text) (interpose " ") @@ -300,7 +300,7 @@ Oh, and before I forget, there is also a macro for doing reverse piping (which c Out previous example would look like this: -``` +```clojure (<| (fold append_text "") (interpose " ") (map to_text) @@ -319,7 +319,7 @@ Well, we haven't really seen that in action yet. It's time to put that theory into practice... with an example: -``` +```clojure (def: (iterate_list f list) (All [a b] (-> (-> a b) (List a) (List b))) (case list @@ -346,7 +346,7 @@ But here, we're pretty much defining a function that takes care of all the cerem You could use it like this: -``` +```clojure (iterate_list (n.* 5) (list 0 1 2 3 4 5 6 7 8 9)) ## => (list 0 5 10 15 20 25 30 35 40 45) diff --git a/documentation/book/the_lux_programming_language/chapter_6.md b/documentation/book/the_lux_programming_language/chapter_6.md index 145aff4a1..a68d791e4 100644 --- a/documentation/book/the_lux_programming_language/chapter_6.md +++ b/documentation/book/the_lux_programming_language/chapter_6.md @@ -8,7 +8,7 @@ We've talked about Lux types already, but only in a very high-level way. On this chapter, you'll see how types are constructed, and hopefully that will give you some insight to understand better the subjects of later chapters. -``` +```clojure (type: #export #rec Type (#Primitive Text (List Type)) (#Sum Type Type) @@ -39,7 +39,7 @@ Let's go over each of them. --- -``` +```clojure (#Primitive Text (List Type)) ``` @@ -47,7 +47,7 @@ This is what connects Lux's type-system with the host platform's. These types re --- -``` +```clojure (#Sum Type Type) (#Product Type Type) ``` @@ -66,7 +66,7 @@ What do I mean? Well, let me show you. To the left, you'll see the type as it's written in normal Lux code, and to the right you'll see the type value it generates. -``` +```clojure (|) => Nothing (| Bit) => Bit (| Bit Int) => (#Sum Bit Int) @@ -122,7 +122,7 @@ You might think that dummy values are, well, _dumb_, but they show up all the ti Consider the `Maybe` type: -``` +```clojure (type: #export (Maybe a) #None (#Some a)) @@ -132,7 +132,7 @@ The `#Some` tag holds values of type `a`, but what does `#None` hold? Nothing? Well, `Maybe` is a variant, which means it's a `#Sum`, which looks like this: -``` +```clojure (#Sum Type Type) ``` @@ -142,7 +142,7 @@ Well, `Any`thing, really. So the type definition for `Maybe` is equivalent to this: -``` +```clojure (type: #export (Maybe a) (#None Any) (#Some a)) @@ -158,7 +158,7 @@ So `#None` is equivalent to `(#None [])`. --- -``` +```clojure (#Function Type Type) ``` @@ -178,7 +178,7 @@ Yep, that's a direct consequence of this theoretical model. --- -``` +```clojure (#Parameter Nat) ``` @@ -188,7 +188,7 @@ We'll talk about those later. But, suffice it to say that `#Parameter` helps the --- -``` +```clojure (#Var Nat) ``` @@ -202,7 +202,7 @@ Type-variables, however, cannot be _re-bound_ once they have been set, to avoid --- -``` +```clojure (#Ex Nat) ``` @@ -216,7 +216,7 @@ It may sound like a useless thing, but it can power some advanced techniques. --- -``` +```clojure (#UnivQ (List Type) Type) ``` @@ -228,7 +228,7 @@ The other `Type` there is the _body_ of the universal quantification. To understand better what's going on, let's transform the type of our `iterate_list` function from [Chapter 5](chapter_5.md) into its type value. -``` +```clojure (All [a b] (-> (-> a b) (List a) (List b))) ## => @@ -246,7 +246,7 @@ Also, `a` and `b` are just nice syntactic labels that get transformed into `#Par --- -``` +```clojure (#ExQ (List Type) Type) ``` @@ -258,7 +258,7 @@ Whereas universal quantification works with type-variables, existential quantifi --- -``` +```clojure (#Apply Type Type) ``` @@ -274,7 +274,7 @@ For multi-parameter types, like `Dictionary` (from `lux/data/collection/dictiona --- -``` +```clojure (#Named Name Type) ``` diff --git a/documentation/book/the_lux_programming_language/chapter_7.md b/documentation/book/the_lux_programming_language/chapter_7.md index aed8617b9..49cae9980 100644 --- a/documentation/book/the_lux_programming_language/chapter_7.md +++ b/documentation/book/the_lux_programming_language/chapter_7.md @@ -42,7 +42,7 @@ They provide a description of the functionality expected of proper implementatio Here's an example: -``` +```clojure (interface: #export (Order a) (: (Equivalence a) &equivalence) @@ -72,7 +72,7 @@ If interfaces are record types, then that means implementations must be actual r Let's take a look at how you make one: -``` +```clojure (implementation: #export order (Order Frac) (def: &equivalence ..equivalence) (def: < ..<)) @@ -86,7 +86,7 @@ For implementations, the convention is just to name them as lower-cased versions Here is another example, from the `lux/data/collection/list` module: -``` +```clojure (implementation: #export monoid (All [a] (Monoid (List a))) @@ -123,7 +123,7 @@ It's time to get them out and use them. There are 2 main ways to use the stuff inside your implementations: `open:` and `\`. Let's check them out. -``` +```clojure ## Opens an implementation and generates a definition for each of its members (including nested members). ## For example: (open library/lux/math/number/int.order "i::.") @@ -137,7 +137,7 @@ You may also give it an optional prefix for the definitions, in case you want to You might want to check out [Appendix C](appendix_c.md) to discover a pattern-matching macro version of `open:` called `^open`. -``` +```clojure ## Allows accessing the value of a implementation's member. (: (-> Int Text) (\ library/lux/math/number/int.decimal encode)) @@ -161,7 +161,7 @@ For more information about that, head over to [Appendix F](appendix_f.md) to rea I can't emphasize enough that _implementations_ are values. And to exemplify it for you, here's a function from the `lux/abstract/monad` module that takes in an implementation (among other things) and uses it within its code: -``` +```clojure (def: #export (map monad f xs) (All [M a b] (-> (Monad M) (-> a (M b)) (List a) (M (List b)))) diff --git a/documentation/book/the_lux_programming_language/chapter_8.md b/documentation/book/the_lux_programming_language/chapter_8.md index 4d54e9eb9..61045cec9 100644 --- a/documentation/book/the_lux_programming_language/chapter_8.md +++ b/documentation/book/the_lux_programming_language/chapter_8.md @@ -28,7 +28,7 @@ That wrapper happens to be a type, as **all** functor wrappers are types. But not just any type. You see, functors have requirements. -``` +```clojure (interface: #export (Functor f) (: (All [a b] (-> (-> a b) (f a) (f b))) @@ -47,7 +47,7 @@ Not every parameterized type can be a functor, but if the type is something that Remember that `Maybe` type we talked about? Let's see how it plays with `Functor`. -``` +```clojure (type: (Maybe a) #.None (#.Some a)) @@ -59,7 +59,7 @@ We've seen `Maybe` before, but now we can check out how it's implemented. Here is its `Functor` implementation. -``` +```clojure (implementation: #export functor (Functor Maybe) @@ -73,7 +73,7 @@ Here is its `Functor` implementation. We'll know how everything fits if we fill in the blanks for `map`'s type: -``` +```clojure (All [a b] (-> (-> a b) (Maybe a) (Maybe b)) ``` @@ -90,7 +90,7 @@ Oh, and remember our `iterate_list` function from [chapter 5](chapter_5.md)? Turns out, that's just the `Functor` implementation from `lux/data/collection/list`: -``` +```clojure (implementation: #export functor (Functor List) @@ -118,7 +118,7 @@ I mean, you can use the `list` and `list&` macros to create lists and the `#.Non Well, let me introduce you to `Monad`: -``` +```clojure (interface: #export (Monad m) (: (Functor m) &functor) @@ -142,7 +142,7 @@ To get a taste for it, let's check out another functorial type. Remember what I said about error-handling? -``` +```clojure (type: #export (Try a) (#Failure Text) (#Success a)) @@ -152,7 +152,7 @@ This type expresses errors as `Text` values (and it lives in the `lux/control/tr Here are the relevant `Functor` and `Monad` implementations: -``` +```clojure (implementation: #export functor (Functor Try) @@ -187,7 +187,7 @@ The thing about `Monad` is that, with it, you can use `map` functions that also Let's see that in action: -``` +```clojure (.module: [library [lux #* @@ -210,7 +210,7 @@ _It's magic!_ Not really. It's just the `Monad` for `List`: -``` +```clojure (implementation: #export functor (Functor List) @@ -274,7 +274,7 @@ Time for the VIP treatment. These macros always show up at the right time to saves us from our hurdles! -``` +```clojure (.module: [library [lux #* diff --git a/documentation/book/the_lux_programming_language/chapter_9.md b/documentation/book/the_lux_programming_language/chapter_9.md index acc17e2aa..49ffe48bb 100644 --- a/documentation/book/the_lux_programming_language/chapter_9.md +++ b/documentation/book/the_lux_programming_language/chapter_9.md @@ -22,7 +22,7 @@ Most compilers are just programs that take source code and emit some binary exec The `Lux` type enters the stage. -``` +```clojure (type: #export Lux {#info Info #source Source @@ -70,7 +70,7 @@ I won't go into detail about what's available, but you'll quickly get an idea of However, one thing I _will_ say is that those functions rely heavily on the `Meta` type, which is defined thusly: -``` +```clojure (type: #export (Meta a) (-> Lux (Either Text [Lux a]))) ``` @@ -101,7 +101,7 @@ Another important piece of information you should be aware of is that definition The relevant types in the `library/lux` module are: -``` +```clojure (type: #export Location {#module Text #line Nat @@ -135,7 +135,7 @@ All you need to do is pass in some record syntax, with tags signaling the type o Here's an example from `library/lux`: -``` +```clojure (def: #export (is? reference sample) {#.doc (doc "Tests whether the 2 values are identical (not just 'equal')." "This one should succeed:" diff --git a/documentation/book/the_lux_programming_language/index.md b/documentation/book/the_lux_programming_language/index.md index 17fdd3a7f..6242b7dba 100644 --- a/documentation/book/the_lux_programming_language/index.md +++ b/documentation/book/the_lux_programming_language/index.md @@ -33,6 +33,8 @@ _Where you will learn a new way to organize your data._ * [Chapter 16: Testing](chapter_16.md) _Where you will learn how to avoid annoying bug reports._ +* [Chapter 17: Cross-platform Lux](chapter_17.md) + _Where you will sail to exotic foreign platforms on the S.S. Lux._ * [Conclusion](conclusion.md) * [Appendix A: Import syntax](appendix_a.md) * [Appendix B: Math](appendix_b.md) |