From e858f41dffaee272ffcf4b2cb63a49ad25ebf7d7 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Mon, 15 Mar 2021 15:01:22 -0400 Subject: Highlight namespace dot as a separate token in md.bqn --- docs/doc/based.html | 2 +- docs/doc/embed.html | 2 +- docs/doc/fromDyalog.html | 4 +- docs/doc/fromJ.html | 114 +++++++++++++++++++++++------------------------ docs/doc/namespace.html | 6 +-- docs/doc/oop.html | 20 ++++----- 6 files changed, 74 insertions(+), 74 deletions(-) (limited to 'docs/doc') diff --git a/docs/doc/based.html b/docs/doc/based.html index ced213c8..36ce2af8 100644 --- a/docs/doc/based.html +++ b/docs/doc/based.html @@ -48,4 +48,4 @@

Versus the boxed array model

The boxed array model of SHARP APL, A+, and J is an inductive system like BQN's. But this model uses arrays as the base case: numeric and character arrays are the simplest kind of data allowed, and "a number" means a rank-0 numeric array. The inductive step is the array of boxes; as with numbers "a box" is simply a rank-0 array of boxes.

Numeric and character arrays in this system have depth 0. In general these correspond to arrays of depth 1 in BQN, but because there's no lower depth they are also used where BQN atoms would appear. For example, both Shape ($) and Length (#) return depth-0 results in J. For an array a with rank at least 1, the length #a is exactly [/ $ a, while the identical BQN code ˝ a returns not a but < a. Like the nested model, the boxed model can hide depth issues that occur at lower depths but generally reveals them at higher depths.

-

The boundary at depth 0 will tend to cause inconsistencies and confusion in any array language, and boxed array languages push this boundary up a level. This leads to the programmer spending more effort managing boxes: for example, to reverse each list in a list of lists, the programmer can use reverse under open, |. &. >. But to find the lengths of each of these lists, # &. > would yield a boxed list, which is usually not wanted, so # @ > is needed instead. BQN shows that a system that doesn't require these distinctions is possible, as a BQN programmer would use ¨ and ¨.

+

The boundary at depth 0 will tend to cause inconsistencies and confusion in any array language, and boxed array languages push this boundary up a level. This leads to the programmer spending more effort managing boxes: for example, to reverse each list in a list of lists, the programmer can use reverse under open, |. &. >. But to find the lengths of each of these lists, # &. > would yield a boxed list, which is usually not wanted, so # @ > is needed instead. BQN shows that a system that doesn't require these distinctions is possible, as a BQN programmer would use ¨ and ¨.

diff --git a/docs/doc/embed.html b/docs/doc/embed.html index 2a2ca1c7..bd3bb94c 100644 --- a/docs/doc/embed.html +++ b/docs/doc/embed.html @@ -36,7 +36,7 @@

In the programs above we've used numbers and functions of one argument, which mean the same thing in BQN and JS. This isn't the case for all types: although every BQN value is stored as some JS value, the way it's represented may not be obvious and there are many JS values that don't represent any BQN value and could cause errors. BQN operations don't verify that their inputs are valid BQN values (this would have a large performance cost), so it's up to the JS programmer to make sure that values passed in are valid. To do this, you need to know the encodings for each of the six BQN types.

The two atomic data values are simple: numbers are just JS numbers, and characters are strings containing a single code point. Arrays are JS arrays, but with some extra information. Since JS arrays are 1-dimensional, a BQN array a is stored as the element list a. Its shape a, a list of numbers, is a.sh in JS (the shape isn't necessarily a BQN array so it doesn't have to have a sh property). Optionally, its fill element is a.fill. Note that a BQN string is not a JS string, but instead an array of BQN characters, or JS strings. To convert it to a JS string you can use str.join("").

There are two utilities for converting from JS to BQN data: list([…]) converts a JS array to a BQN list, and str("JS string") converts a string.

-

Operations are all stored as JS functions, with one or two arguments for the inputs. The type is determined by the .m property, which is 1 for a 1-modifier and 2 for a 2-modifier, and undefined or falsy for a function. Functions might be called with one or two arguments. In either case, 𝕩 is the first argument; 𝕨, if present, is the second. Note that F(x,w) in JS corresponds to w F x in BQN, reversing the visual ordering of the arguments! For modifiers there's no such reversal, as 𝕗 is always the first argument, and for 2-modifiers 𝕘 is the second argument. As in BQN, a modifier may or may not return a function.

+

Operations are all stored as JS functions, with one or two arguments for the inputs. The type is determined by the .m property, which is 1 for a 1-modifier and 2 for a 2-modifier, and undefined or falsy for a function. Functions might be called with one or two arguments. In either case, 𝕩 is the first argument; 𝕨, if present, is the second. Note that F(x,w) in JS corresponds to w F x in BQN, reversing the visual ordering of the arguments! For modifiers there's no such reversal, as 𝕗 is always the first argument, and for 2-modifiers 𝕘 is the second argument. As in BQN, a modifier may or may not return a function.

Operations may have some extra properties set that aren't terribly important for the JS programmer: for each primitive p, p.glyph gives its glyph, and for a compound operation o such as a train, or a modifier with bound operands, o.repr() decomposes it into its parts. It wouldn't make sense to define either of these properties for a function created in JS.

Other functionality

The BQN script also contains the function fmt, which takes a BQN value for its argument and returns a string displaying it.

diff --git a/docs/doc/fromDyalog.html b/docs/doc/fromDyalog.html index 5a4f6241..9a64afaa 100644 --- a/docs/doc/fromDyalog.html +++ b/docs/doc/fromDyalog.html @@ -260,7 +260,7 @@ Dyalog ¨ -. +. @@ -319,7 +319,7 @@ ˜ f.g f˝g1 - .f f + .f f Ag Ag fB fB fg fg diff --git a/docs/doc/fromJ.html b/docs/doc/fromJ.html index a39e156c..3c5ad0a2 100644 --- a/docs/doc/fromJ.html +++ b/docs/doc/fromJ.html @@ -51,7 +51,7 @@ -NB. +NB. # @@ -61,7 +61,7 @@ ' creates characters -=. and =: +=. and =: and to define; to modify @@ -136,13 +136,13 @@ % ^ %: -<. ->. +<. +>. <: >: [ ] -|. +|. |: @@ -168,10 +168,10 @@ Monad /:~ \:~ --. +-. #@$ # -L. +L. $ , ; @@ -179,13 +179,13 @@ Dyad -*. -+. -+-. +*. ++. ++-. = ~: -: --.@-: +-.@-: $ , ,: @@ -208,16 +208,16 @@ Monad <\ -<\. +<\. i. #{.(_1-#){.] -@#{.(1+#){.] -I. +I. Dyad -{. -}. +{. +}. ]\ #@]{., -@#@]{.,~ @@ -245,29 +245,29 @@ Monad /: /: -{. +{. 0{::, -i.~~. +i.~~. ~: -~. -</.i.@# +~. +</.i.@# Dyad -I. -I.&:- +I. +I.&:- { {:: i. e. -E. -</. +E. +</. -

Most of BQN's combinators have J equivalents. The J equivalent "_ for ˙ assumes a noun operand, but ˙ makes a constant function for any operand. has arguments reversed relative to @., and uses an actual array of functions rather than gerunds. Besides these, BQN's is like a J hook, that is, FG is (F G), and applies in the opposite direction.

+

Most of BQN's combinators have J equivalents. The J equivalent "_ for ˙ assumes a noun operand, but ˙ makes a constant function for any operand. has arguments reversed relative to @., and uses an actual array of functions rather than gerunds. Besides these, BQN's is like a J hook, that is, FG is (F G), and applies in the opposite direction.

@@ -289,9 +289,9 @@ - + - + @@ -316,9 +316,9 @@ - - - + + + @@ -358,13 +358,13 @@ - + - - + + - + @@ -392,7 +392,7 @@ - + @@ -439,7 +439,7 @@ - + @@ -449,7 +449,7 @@ - + @@ -459,7 +459,7 @@ - + @@ -469,7 +469,7 @@ - + @@ -479,7 +479,7 @@ - + @@ -494,7 +494,7 @@ - + @@ -544,7 +544,7 @@ - + @@ -559,7 +559,7 @@ - + @@ -569,7 +569,7 @@ - + @@ -584,7 +584,7 @@ - + @@ -599,12 +599,12 @@ - + - + @@ -615,7 +615,7 @@
~ @: &:&.:&.: :@.@. ::
J&.>&.>/&.>/&.>&.>/&.>/ / /\ "_1* % ^^.^. %:<.>.<.>. [ ]|.|. |:
~ @: &:&.:&.: : " L:
+.+.
¬∨
*.*.
¬∧
-.-. ¬ ¬∊/⊣
%.%. +˝×1
~.~.
,.,. ˘ ˘
{.{.
}.}. 1
".". •Eval
E.E.
⊣-1+⌽
I.I. /
L.L.
-

Some J modifier expressions are translated below. BQN doesn't keep track of the rank of functions, so the "close" compositions @ & &. have no BQN equivalents: instead, specify a rank after composing.

+

Some J modifier expressions are translated below. BQN doesn't keep track of the rank of functions, so the "close" compositions @ & &. have no BQN equivalents: instead, specify a rank after composing.

@@ -625,7 +625,7 @@ - + @@ -633,7 +633,7 @@ - + @@ -641,7 +641,7 @@ - + @@ -649,23 +649,23 @@ - + - + - + - + - + @@ -681,7 +681,7 @@ - + @@ -691,7 +691,7 @@ - + diff --git a/docs/doc/namespace.html b/docs/doc/namespace.html index 17ed7cf6..c6f19582 100644 --- a/docs/doc/namespace.html +++ b/docs/doc/namespace.html @@ -10,7 +10,7 @@

The following quick example shows a few ways to use a namespace returned by •Import:

ns  •Import "file.bqn"
 something, abbrabbreviation  ns  # Destructure
-ns.DoThing 6                         # Dot syntax
+ns.DoThing 6                         # Dot syntax
 

An here's how the contents of file.bqn might look in order to define the variables used above:

something, DoThing     # Declare exports
@@ -42,9 +42,9 @@
 

The arrows used for importing don't indicate that the surrounding block is a namespace or export variables. However, a single statement can both import and export, if it's a destructuring assignment and the main assignment arrow is .

two, vars  •Import "stuff.bqn"
 
-

The second way to get a value (just one at a time) from a namespace is dot syntax: write the namespace, then a dot ., then another name.

+

The second way to get a value (just one at a time) from a namespace is dot syntax: write the namespace, then a dot ., then another name.

example.b
 
-{n7}.n
+{n7}.n
 

The syntax is any subject followed by a dot and then a name. This can be chained like a.b.c if a namespace has a value that is also a namespace (and so on).

diff --git a/docs/doc/oop.html b/docs/doc/oop.html index a683a550..c2c597db 100644 --- a/docs/doc/oop.html +++ b/docs/doc/oop.html @@ -65,7 +65,7 @@
&.>&.> ¨
F˝ y
x F&.>/ yx F&.>/ y x F y
x Fr y where r is F's left rank
F`G`H@.CF`G`H@.C CF,G,H
x(y) z
x F/ . G yx F/ . G y x F˝G1 y
F :. GF :. G {𝕊: 𝕨F𝕩; 𝕊: 𝕨G𝕩}
<;._1<;._1 ((1-˜¬×+`)=)⊔⊢
x {.!.f yx {.!.f y y » xf
x |.!.f yx |.!.f y x f« y, or (-x) f» y if 𝕩<0
/./. (+⌜´¨)
<˘
\.\. ¯1↓↓

Objects

-

An object in BQN is simply a namespace: its fields and methods are variables in the namespace, and one of these can be accessed outside of the namespace with dot syntax if it's exported with . Unexported variables are instance-private in OOP parlance, meaning that only they're only visible to the object containing them. They could be utilities, or hold state for the object. As an example, the object below implements the Tower of Hanoi puzzle with five disks. You can view the state (a list of disks occupying each of the three rods) with towerOfHanoi.View, or move the top disk from one rod to another with towerOfHanoi.Move.

+

An object in BQN is simply a namespace: its fields and methods are variables in the namespace, and one of these can be accessed outside of the namespace with dot syntax if it's exported with . Unexported variables are instance-private in OOP parlance, meaning that only they're only visible to the object containing them. They could be utilities, or hold state for the object. As an example, the object below implements the Tower of Hanoi puzzle with five disks. You can view the state (a list of disks occupying each of the three rods) with towerOfHanoi.View, or move the top disk from one rod to another with towerOfHanoi.Move.

towerOfHanoi  {
   l  ¨500
   View  {𝕤
@@ -85,15 +85,15 @@
 

Two fields l and Transfer aren't exported, for two different reasons. l encodes the state of the tower, but it's often better to expose it with the function View instead to allow the internal representation to be changed freely. Transfer is just a utility function. While it's not dangerous to use outside of the object, there's no reason to expose it through towerOfHanoi's interface. If it's wanted in another place it should be moved to a common location.

Here are the results of a few applications of these functions.

    t  towerOfHanoi
-    t.View@
+    t.View@
   0 1 2 3 4  ⟨⟩ ⟨⟩ 
-    t.Move 02
+    t.Move 02
   1 2 3 4  ⟨⟩  0  
-    t.Move 12
+    t.Move 12
 ! "No disk to move"
-    t.Move 01
+    t.Move 01
   2 3 4   1   0  
-    t.Move 21
+    t.Move 21
   2 3 4   0 1  ⟨⟩ 
 

Classes

@@ -119,18 +119,18 @@
MakeQueue  {𝕤
   the{SetN{h𝕩}}
   Node{v𝕩ne  SetN{n𝕩}}
-  Push{t.SetN nNode 𝕩  tn}
+  Push{t.SetN nNode 𝕩  tn}
   Pop {𝕤vh.v{t𝕩}(e=)hh.nv}
 }
 
-

Unlike a stack, a node's successor isn't known when it's created, and it has to be set. You might be inclined to make n settable directly, but we'll get more mileage out of a setter function SetN. This allows us to create a pseudo-node e (for "empty") indicating there are no values in the queue. Because it has no .v field, if h is e then Pop gives an error (but in a real implementation you'd want to test explicitly instead in order to give an appropriate error message). In fact it doesn't have an n field, and essentially uses the queue head h instead. With this empty "node", the queue definition is straightforward. The only tricky part to remember is that if Pop removes the last node, resulting in e=h, then the tail has to be set to e as well, or it will keep pointing to the removed node and cause bugs.

+

Unlike a stack, a node's successor isn't known when it's created, and it has to be set. You might be inclined to make n settable directly, but we'll get more mileage out of a setter function SetN. This allows us to create a pseudo-node e (for "empty") indicating there are no values in the queue. Because it has no .v field, if h is e then Pop gives an error (but in a real implementation you'd want to test explicitly instead in order to give an appropriate error message). In fact it doesn't have an n field, and essentially uses the queue head h instead. With this empty "node", the queue definition is straightforward. The only tricky part to remember is that if Pop removes the last node, resulting in e=h, then the tail has to be set to e as well, or it will keep pointing to the removed node and cause bugs.

Composition

BQN classes don't support inheritance because there's no way to extend an existing class with new fields. But a lot of OOP enthusiasts these days are promoting composition over inheritance, and here BQN does pretty well. Forwarding methods from another class is as simple as a multiple assignment, like View below (in a real program undoableTowerOfHanoi should almost certainly be a class, but I introduced towerOfHanoi before classes, and I'm not about to write it again just to add an 𝕤).

undoableTowerOfHanoi  {
   PushPop  MakeStack@     # Copy methods as private
   View  ttowerOfHanoi   # Copy and export
-  Move  t.Move  Push
-  Undo  t.MovePop
+  Move  t.Move  Push
+  Undo  t.MovePop
 }
 

This class composes a Tower of Hanoi with an undo stack that stores previous moves. To undo a move from a to b, it moves from b to a, although if you felt really fancy you might define Move in towerOfHanoi instead with 𝕊𝕩: 𝕊⌽𝕩.

-- cgit v1.2.3