From afc086a54b9f37acd4d90ff6cc607ab3008c78f9 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Sat, 9 Oct 2021 21:58:01 -0400 Subject: Predicate documentation --- docs/doc/block.html | 29 +++++++++++++++++++++++++++++ docs/doc/control.html | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/doc/block.html b/docs/doc/block.html index d3eb2bb8..9ae75ef7 100644 --- a/docs/doc/block.html +++ b/docs/doc/block.html @@ -213,6 +213,35 @@ ERROR }

These case-style headers function exactly the same as if they were preceded by π•Š, and can be mixed with other kinds of headers.

+

Predicates

+

Destructuring with a header is quite limited, only allowing matching structure and data with exact equality. A predicate, written with ?, allows you to test an arbitrary property before evaluating the rest of the body, and also serves as a limited kind of control flow. It can be thought of as an extension to a header, so that for example the following function requires the argument to have a single element and for that element to be less than zero before using the first body 1+𝕩. Otherwise it moves to the next one, an unconditional 𝕩.

+↗️
    CheckPair ← { π•ŠβŸ¨a,b⟩: a<b? "ok" ; "not ok" }
+
+    CheckPair ⟨3,8⟩    # Fails destructuring
+"ok"
+    CheckPair ⟨1,4,5⟩  # Not a pair
+"not ok"
+    CheckPair ⟨3,¯1⟩   # Not ascending
+"not ok"
+
+

The body where the predicate appears doesn't need to start with a header, and there can be other statements before it. In fact, ? functions just like a separator (like β‹„ or ,) with a side effect.

+↗️
    { rβ†βŒ½π•© β‹„ 't'=βŠ‘r ? r ; 𝕩 }Β¨ "test"β€Ώ"this"
+⟨ "tset" "this" ⟩
+
+

So r is the reversed argument, and if its first character (the last one in 𝕩) is 't' then it returns r, and otherwise we abandon that line of reasoning and return 𝕩. This sounds a lot like an if statement. And { a<b ? a ; b }, which computes a⌊b the hard way, shows how the syntax can be similar to a ternary operator. But ?; is more flexible than that. It can support any number of options, with multiple tests for each oneβ€”the structure below is "if _ and _ then _; else if _ then _; else _".

+↗️
    Thing ← { 𝕩β‰₯3? 𝕩≀8? 2|𝕩 ; 𝕩=0? @ ; ∞ }
+
+    (⊒ ≍ ThingΒ¨) ↕10  # Table of arguments and results
+β”Œβ”€                     
+β•΅ 0 1 2 3 4 5 6 7 8 9  
+  @ ∞ ∞ 1 0 1 0 1 0 ∞  
+                      β”˜
+
+

This structure is still constrained by the rules of block bodies: each instance of ; is a separate scope, so that variables defined before a ? don't survive past the ;.

+↗️
    { 0=n←≠𝕩 ? ∞ ; n } "abc"
+ERROR
+
+

This is the main drawback of predicates relative to guards in APL dfns (also written with ?), while the advantage is that it allows multiple expressions, or extra conditions, after a ?. It's not how I would have designed it if I just wanted to make a syntax for if statements, but it's a natural fit for the header system.

Returns

This feature is not yet included in any BQN implementation.

The glyph β†’ indicates an early return from a block. It must be preceded either by one of the self-reference special names π•Š or 𝕣 or by an internal name for a containing block. The combination of name and return tokenβ€”like Fβ†’, let's sayβ€”is a function that returns from the current instance of the indicated block. If that instance has already returned, then it instead results in an error.

diff --git a/docs/doc/control.html b/docs/doc/control.html index ae1ce1e4..3c3c2f1a 100644 --- a/docs/doc/control.html +++ b/docs/doc/control.html @@ -55,7 +55,7 @@

There's no reason the condition in an if statement from the previous section has to be boolean: it could be any natural number, causing the action to be repeated that many times. If the action is never performed, the result is the statement's argument, and otherwise it's the result of the last time the action was performed.

Another option is to use a for-each statement with an argument of ↕n: in this case the result is the list of each action's result.

If-Else

-

In most cases, the easy way to write an if-else statement is with predicates:

+

In most cases, the easy way to write an if-else statement is with predicates:

{
   threshold < 6 ?
   a ↩ Small threshold ;  # If predicate was true
-- 
cgit v1.2.3