aboutsummaryrefslogtreecommitdiff
path: root/documentation/book
diff options
context:
space:
mode:
Diffstat (limited to 'documentation/book')
-rw-r--r--documentation/book/the_lux_programming_language/appendix_d.md156
1 files changed, 156 insertions, 0 deletions
diff --git a/documentation/book/the_lux_programming_language/appendix_d.md b/documentation/book/the_lux_programming_language/appendix_d.md
new file mode 100644
index 000000000..5935ac5c3
--- /dev/null
+++ b/documentation/book/the_lux_programming_language/appendix_d.md
@@ -0,0 +1,156 @@
+# Appendix D: The art of piping
+
+I'm a big fan of piping.
+
+No kidding.
+
+Piping is my favorite way of writing code.
+
+It's almost like a game to me.
+
+I try to figure out ways to get my code to be more pipe-sensitive, to see how far I can get while piping my code.
+
+ My personal record is 14 steps.
+
+## Piping macros in the standard library
+
+Anyhow, after looking at some of the innovations in Clojure on the piping department, I decided to come up with my own tricks to try to get Lux to become a piping superpower.
+
+I added the `library/lux/control/pipe` module, which contains several macros meant to be used within the `|>` macro, and which extend it with awesome capabilities.
+
+Take a look at these babies:
+
+```
+... Loops for pipes.
+... Both the testing and calculating steps are pipes and must be given inside tuples.
+(|> 1
+ (loop> [(n.< 10)]
+ [++]))
+```
+
+`loop>` takes a test _tuple_ and a body _tuple_.
+
+The reason is that each of those tuples represents the steps on an implicit piping macro (_oh, yeah!_).
+
+So `[(n.< 10)]` is like `(|> value (n.< 10))`, and `[++]` is like `(|> value ++)`.
+
+Which value? Whatever has been piped into `loop>` from the underlying `|>` (in this case, the value `1`).
+
+---
+
+```
+... 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.
+(|> 5
+ (cond> [i.even?] [(i.* 2)]
+ [i.odd?] [(i.* 3)]
+ ... else branch
+ [(new> -1 [])]))
+```
+
+We have looping, and now we have branching; with a `cond`-inspired piping macro (complete with _else_ branch, just in case).
+
+But what's that thing over there? That `new>` thing?
+
+Well, it's another piping macro. Of course!
+
+```
+... Ignores the piped argument, and begins a new pipe.
+(|> 20
+ (i.* 3)
+ (i.+ 4)
+ (new> 0 [++]))
+```
+
+`new>` establishes a new piping sequence that ignores any previous one.
+
+Useful in certain kinds of situations.
+
+---
+
+```
+... Gives a name to the piped-argument, within the given expression.
+(|> 5
+ (let> @ (+ @ @)))
+```
+
+`let>` binds the current value piped into it so you can refer to it multiple times within it's body.
+
+Pretty nifty, huh?
+
+---
+
+```
+... Pattern-matching for pipes.
+... The bodies of each branch are NOT pipes; just regular values.
+(|> 5
+ (case> 0 "zero"
+ 1 "one"
+ 2 "two"
+ 3 "three"
+ 4 "four"
+ 5 "five"
+ 6 "six"
+ 7 "seven"
+ 8 "eight"
+ 9 "nine"
+ _ "???"))
+```
+
+Yeah, that's right!
+
+I just couldn't resist rolling full-blown pattern-matching into this.
+
+You'll thank me later.
+
+---
+
+```
+... Monadic pipes.
+... Each steps in the monadic computation is a pipe and must be given inside a tuple.
+(|> 5
+ (do> identity.monad
+ [(i.* 3)]
+ [(i.+ 4)]
+ [+]))
+```
+
+And just to show you I'm serious, I did the unthinkable.
+
+Piped macro expressions!
+
+## How to make your own piping macros
+
+They're easier to make than pattern-matching macros.
+
+All you need is a macro that takes anything you want as parameters, but always takes as its last argument _the computation so far_, as it has been constructed by the `|>` macro prior to the call to your piping macro.
+
+As an example, here's the definition for `let>`:
+
+```
+(syntax: .public (let> [binding <code>.any
+ body <code>.any
+ prev <code>.any])
+ (in (list (` (let [(~ binding) (~ prev)]
+ (~ body))))))
+```
+
+---
+
+All this looks like madness, but I just couldn't contain myself.
+
+Piping is one of the few ways of writing code that just amuses me whenever I do it.
+
+These macros can keep you in the flow while you're writing complex code, so you don't have to switch so much between piping-code and non-piping-code.
+
+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?
+
+```
+(only (|>> (member? forbidden-definitions)
+ not)
+ all_definitions)
+```
+