aboutsummaryrefslogtreecommitdiff
path: root/documentation/book
diff options
context:
space:
mode:
authorEduardo Julian2021-08-21 04:06:54 -0400
committerEduardo Julian2021-08-21 04:06:54 -0400
commit1ea83ecadccc5adee1bdb35bd11527c3982c015e (patch)
treeb2a701e6eb14469d55a4f88af3f398a7d7056121 /documentation/book
parent374ccf07246484eb7beb2cd87f3fc88396373ee1 (diff)
Can now produce arbitrary code fragments statically by evaluating arbitrary expressions at compile-time.
Diffstat (limited to 'documentation/book')
-rw-r--r--documentation/book/the_lux_programming_language/appendix_a.md247
-rw-r--r--documentation/book/the_lux_programming_language/chapter_1.md1
2 files changed, 247 insertions, 1 deletions
diff --git a/documentation/book/the_lux_programming_language/appendix_a.md b/documentation/book/the_lux_programming_language/appendix_a.md
new file mode 100644
index 000000000..29a84a9df
--- /dev/null
+++ b/documentation/book/the_lux_programming_language/appendix_a.md
@@ -0,0 +1,247 @@
+# Appendix A: Import syntax
+
+You've already seen some import syntax, but now you'll see all the options available.
+
+If you recall [Chapter 1](chapter_1.md), there was this example code:
+
+```
+(.module:
+ [library
+ [lux #*
+ [program (#+ program:)]
+ ["." debug]
+ [control
+ ["." io]]]])
+```
+
+Here, we're importing the `library/lux` module.
+The `#*`/`#all` option means _locally import every definition exported by the `library/lux` module_.
+
+This allows usage of those definitions without having to give them the `library/lux.` prefix, or even the `.` shortcut prefix.
+
+This may cause some issues if you import 2 definitions with the same name from different modules; or if you get a definition from one module, but then write your own definition with the same name in your code.
+In those circumstances, the compiler will complain, saying that you can't re-define `X`; where `X` is the name of the definition.
+
+Then, we import `library/lux/program`, but we **only** import locally the `program:` definition.
+That is what the `#+`/`#only` option allows.
+
+ There is also a `#-`/`#exclude` option which means locally import everything **except** the specified definitions_.
+ You could use it like this: `[program (#- foo bar baz)]`
+
+Finally, we import both the `library/lux/debug` and `library/lux/control/io` modules.
+In neither case do we import any of their definitions locally.
+We also give both of those modules local aliases.
+That is what that `"."` syntax does.
+The `.module:` macro recognizes that syntax for aliases and replaces the dot/period with the import name directly to the right.
+That means:
+* `"."` + `debug` = `debug`
+* `"."` + `io` = `io`
+
+This might not seem like a big deal, but the aliasing syntax allows you to give imports arbitrary names, so long as you take into account the substitutions that may happen.
+
+So, for example:
+* `"my_."` + `debug` = `my_debug`
+* `"._."` + `io` = `io_io`
+
+It is also important to note that while imports can be nested for convenience, they don't have to be.
+
+The `.module:` declaration could just as easily been written like this:
+
+```
+(.module:
+ [library/lux #*]
+ [library/lux/program (#+ program:)]
+ ["debug" library/lux/debug]
+ ["io" library/lux/control/io])
+```
+
+You might also guess that `library` was not imported as a module because it was neither given an alias, not had any definitions specified as local imports.
+Any module-path fragments included in the import syntax without such options will not be imported and will simply be assumed to be part of the module-paths of the sub-modules specified under them.
+
+---
+
+It is also possible to have the `.module:` macro open interface implementations for you when importing the modules that contain them.
+For example:
+
+```
+(.module:
+ [library
+ [lux #*
+ [data
+ [collection
+ ["." list ("#::." functor monoid)]]]]])
+```
+
+The import above would locally import:
+* `list::map`, from `functor`.
+* `list::identity`, from `monoid`.
+* `list::compose`, from `monoid`.
+
+Here, we can also see some additional syntax for aliasing.
+First of all, when opening implementations, aliasing syntax is used to determine the names of the local implementation imports.
+The `.` is replaced with the name of the implementation member.
+The `#` is bound to the name of the _context_ of the import.
+In this case, the implementations are coming from the `library/lux/data/collection/list` module, so that is the context.
+And since that module has been imported with the local alias `list`, that is the name that replaces the `#` in the aliasing syntax for the implementation imports.
+And that is how we end up with the list of names I enumerated above.
+
+The `#` syntax for aliasing can also be used between modules, and not just when importing implementation members.
+
+For example:
+
+```
+(.module:
+ [library
+ [lux #*
+ [data
+ ["." collection #_
+ ["#/." list ("#::." functor monoid)]]]]])
+```
+
+Would locally import:
+* `collection/list::map`, from `functor`.
+* `collection/list::identity`, from `monoid`.
+* `collection/list::compose`, from `monoid`.
+
+The context between module imports corresponds to the closest ancestor path which has itself been aliased.
+Non-aliased paths don't count as context.
+
+This means:
+
+```
+(.module:
+ [library
+ [lux #*
+ ["." data #_
+ [collection
+ ["#/." list ("#::." functor monoid)]]]]])
+```
+
+Would locally import:
+* `data/list::map`, from `functor`.
+* `data/list::identity`, from `monoid`.
+* `data/list::compose`, from `monoid`.
+
+ Also, that `#_`/`#ignore` syntax you may have noticed means _do not import this module; just give it an alias I can refer to later as a context_.
+
+I should also note that you can **both** locally import definitions and open implementations as parts of the same module import.
+
+For example:
+
+```
+(.module:
+ [library
+ [lux #*
+ [data
+ [collection
+ ["." list (#+ repeated size) ("#::." monad)]]]]])
+```
+
+---
+
+Another important feature of module imports is relative addressing, which comes in 2 flavors.
+
+For the first one, suppose you have the following directory structure:
+
+```
+program
+ foo
+ bar
+ baz
+ quux
+test
+ foo
+ bar
+ baz
+ quux
+```
+
+And you're writing code in the `program/foo/baz` module.
+
+You can import other modules in the hierarchy like this:
+
+```
+... In program/foo/baz
+(.module:
+ [library
+ [lux #*]]
+ ["." /quux] ... program/foo/baz/quux, aliased as /quux
+ ["." //bar] ... program/foo/bar, aliased as //bar
+ ["." ///] ... program, aliased as ///
+ )
+```
+
+A single forward slash (`/`) signifies _"this module"_ in the hierarchy, so anything after the forward slash is assumed to be under _this module_.
+Two forward slashes (`//`) signify _"the module above"_, and any forward slash after that allows you to go further up the hierarchy.
+In the case of `program`, it's enough to just specify three forward slashes (`///`) for the `.module:` macro to know which module you're referring to.
+
+You can think about it like this:
+
+* `program/foo/baz` + `/` + `quux` = `program/foo/baz/quux`
+* `program/foo/baz` + `//` + `bar` = `program/foo` + `/` + `bar` = `program/foo/bar`
+* `program/foo/baz` + `///` = `program/foo` + `//` = `program` + `/` = `program`
+
+Also, this relative path syntax can be nested, like so:
+
+```
+... In program/foo/baz
+(.module:
+ [library
+ [lux #*]]
+ [/
+ ["." quux]] ... program/foo/baz/quux, aliased as quux
+ [//
+ ["." bar] ... program/foo/bar, aliased as bar
+ ]
+ ["." ///] ... program, aliased as ///
+ )
+```
+
+Or even:
+
+```
+... In program/foo/baz
+(.module:
+ [library
+ [lux #*]]
+ [/
+ ["." quux] ... program/foo/baz/quux, aliased as quux
+ [//
+ ["." bar] ... program/foo/bar, aliased as bar
+ ["program" //] ... program, aliased as program
+ ]])
+```
+
+You may have noticed that when importing `program`, we went from `///` to `//`.
+That is because, since it's nested under another `//`, it's relative to `program/foo` instead of `program/foo/baz`, so only 1 step up is necessary instead of the 2 steps a `///` would provide.
+
+---
+
+For the second way to do relative imports, you can see this example:
+
+```
+... In program/foo/baz
+(.module:
+ [library
+ [lux #*]]
+ [\\test
+ ["." /] ... test/foo/baz, aliased as /
+ ]
+ ... Alternatively
+ ["." \\test] ... test/foo/baz, aliased as \\test
+ ... Or
+ [\\
+ [\test
+ ["." /] ... test/foo/baz, aliased as /
+ ]]
+ )
+```
+
+The backslash (`\`) works in the reverse direction to the forward slash (`/`).
+If the forward slash allows you append paths to the back, and to move up the hierarchy from the end; then the backslash allows you to append paths to the front, and the move down the hierarchy from the beginning.
+
+Why would you want such a thing?
+
+Because it allows you to easily establish parallel hierarchies of modules, which is a useful way to separate orthogonal aspects of your program (like the `program` and `test` hierarchies in our example).
+Then, by using this relative syntax, you can refer to one hierarchy from another in an easy way.
+
diff --git a/documentation/book/the_lux_programming_language/chapter_1.md b/documentation/book/the_lux_programming_language/chapter_1.md
index 89aab1d53..9b670ef5c 100644
--- a/documentation/book/the_lux_programming_language/chapter_1.md
+++ b/documentation/book/the_lux_programming_language/chapter_1.md
@@ -53,7 +53,6 @@ These are the steps:
```
(.module:
- {#.doc "This will be our program's main module."}
[library
[lux #*
[program (#+ program:)]