@@ 33,8 33,37 @@ LIBJ_DIR=/directory/containing/sofile jpm install https://git.sr.ht/~subsetpark/
See `eval/eval*` and `j/j*` for details.
-All of the above functions have the same basic signature: they take a *verb*
-and 0, 1, or 2 arguments.
+`jnj` is designed to allow you to use J from within Janet. Thus, it has two
+main functions:
+
+- using Janet to drive evaluation of J commands
+- conversion back and forth between Janet and J datatypes.
+
+To do so, jnj introduces two main abstract types:
+- a J Engine instance
+- a J Array object
+
+All J computations take place within an instance of the J Engine. For
+convenience, a default instance is created at import time and available at
+`jnj/j-engine`. The `eval` and `j` commands both use this default instance,
+while `eval*` and `j*` allow you to specify your own.
+
+All of the above functions have the same basic signature (modulo the presence
+or absence of an engine argument): they take a *verb* and 0, 1, or 2
+arguments.
+
+The difference is that `j` and `j*` will evaluate their J command and return
+native Janet datatypes. `eval` and `eval*`, on the other hand, will return
+the other abstract type, a *J Array*.
+
+J Arrays can be inspected for rank, shape, etc., but they can also be passed
+as arguments to further `eval`/`j` calls. Thus, they're an efficient way to
+perform more complex procedures, involving multiple calls to the J
+interpreter, without having to convert data in and out of the J
+representation. They are also the most efficient and convenient way to create
+multi-dimensional arrays, as opposed to nesting multiple Janet array/tuples.
+
+### `eval`/`j`
The verb can be any J sentence, verb or verb sequence. It can be a symbol or
a string.
@@ 46,10 75,10 @@ repl:3:> (jnj/j "3 4 $ i. 10")
((0 1 2 3) (4 5 6 7) (8 9 0 1))
```
-Arguments should be native Janet terms *or* the result of a `jnj/eval` call.
-If they're present, the verb will be applied to them. If there's a single
-argument, it will be evaluated in the form `<VERB> <X>`. If there are two
-arguments, X and Y, they will be evaluated in the form `<X> VERB <Y>`.
+Arguments should be native Janet terms *or* a J Array. If they're present,
+the verb will be applied to them. If there's a single argument Y, it will be
+evaluated in the form `<VERB> <Y>`. If there are two arguments, X and Y, they
+will be evaluated in the form `<X> VERB <Y>`.
```
repl:4:> (jnj/j "$" [3 4] (range 10))
@@ 63,9 92,43 @@ repl:6:> (jnj/j '$ mat)
(3 4)
```
+In the first example, we evaluate a J sentence using native datatypes and
+return the result as native datatypes. In the second, we evaluate the same
+command and return the result as a J Array, which we can then use as an
+argument in subsequent commands.
+
+## Advanced Usage
+
+### `let-j`
+
+The `let-j`/`let-j*` convenience macros provide a simple wrapper around
+`eval` and `j` which is more expressive and efficient.
+
+The above example could also be written as:
+
+```
+repl:1> (let-j [mat ("$" [3 4] (range 10))]
+ ('$ mat))
+(3 4)
+```
+
+### `to-j-array`
+
+As noted above, JNJ provides the J Array abstract type as a way to
+efficiently store J values. J provides an efficient and terse way to
+construct multi-dimensional arrays; however, if you have some existing Janet
+data which you want to use as an argument to J, you can convert it:
+
+```
+repl:2:> (to-j-array [[1 1 1][2 2 2][3 3 3]])
+<jnj/jvalue float [2/9]>
+repl:3:> (j "+/" _)
+(6 6 6)
+```
+
## jnj
-[eval](#eval), [eval*](#eval-1), [from-j-value](#from-j-value), [j](#j), [j*](#j-1), [j-engine](#j-engine), [jnj-primitives/do](#jnj-primitivesdo), [jnj-primitives/getm](#jnj-primitivesgetm), [jnj-primitives/init](#jnj-primitivesinit), [jnj-primitives/rank](#jnj-primitivesrank), [jnj-primitives/setm](#jnj-primitivessetm), [jnj-primitives/shape](#jnj-primitivesshape), [jnj-primitives/to-j-value](#jnj-primitivesto-j-value), [jnj-primitives/values](#jnj-primitivesvalues), [let-j](#let-j), [let-j*](#let-j-1), [to-j-value](#to-j-value)
+[eval](#eval), [eval*](#eval-1), [from-j-value](#from-j-value), [j](#j), [j*](#j-1), [j-engine](#j-engine), [jnj-primitives/init](#jnj-primitivesinit), [let-j](#let-j), [let-j*](#let-j-1), [to-j-array](#to-j-array)
## eval
@@ 78,7 141,7 @@ repl:6:> (jnj/j '$ mat)
Evaluate `verb` and `args` with the default J engine instance (see `eval*`
for details).
-[1]: jnj.janet#L256
+[1]: jnj.janet#L255
## eval*
@@ 92,7 155,7 @@ Evaluate `verb` with arguments `args` in the context of `je`. Returns a
j-array abstract type which can be used for further evaluations, or converted
into a tuple matrix.
-[2]: jnj.janet#L107
+[2]: jnj.janet#L106
## from-j-value
@@ 107,7 170,7 @@ Turn a j-value abstract type result into a Janet term of the appropriate shape:
- a scalar value
- a matrix of nested tuples
-[3]: jnj.janet#L119
+[3]: jnj.janet#L118
## j
@@ 120,7 183,7 @@ Turn a j-value abstract type result into a Janet term of the appropriate shape:
Evaluate `verb` with `args` in the default J engine instance (see `j*` for
details).
-[4]: jnj.janet#L264
+[4]: jnj.janet#L263
## j*
@@ 135,7 198,7 @@ datatype:
- a matrix of nested tuples for anything with rank > 0
- a Janet atom (string, number) otherwise
-[5]: jnj.janet#L214
+[5]: jnj.janet#L213
## j-engine
@@ 144,107 207,23 @@ datatype:
The default J instance, used by `jnj/j`.
-[6]: jnj.janet#L11
-
-## jnj-primitives/do
-
-**function** | [source][7]
-
-```janet
-<function comment>
-```
-
-
-
-[7]: jnj.janet#L5
-
-## jnj-primitives/getm
-
-**function** | [source][8]
-
-```janet
-<function comment>
-```
-
-
-
-[8]: jnj.janet#L7
+[6]: jnj.janet#L10
## jnj-primitives/init
-**function** | [source][9]
-
-```janet
-<function comment>
-```
-
-
-
-[9]: jnj.janet#L2
-
-## jnj-primitives/rank
-
-**function** | [source][10]
-
-```janet
-<function comment>
-```
-
-
-
-[10]: jnj.janet#L8
-
-## jnj-primitives/setm
-
-**function** | [source][11]
-
-```janet
-<function comment>
-```
-
-
-
-[11]: jnj.janet#L6
-
-## jnj-primitives/shape
-
-**function** | [source][12]
-
-```janet
-<function comment>
-```
-
-
-
-[12]: jnj.janet#L3
-
-## jnj-primitives/to-j-value
-
-**function** | [source][13]
-
-```janet
-<function comment>
-```
-
-
-
-[13]: jnj.janet#L9
-
-## jnj-primitives/values
-
-**function** | [source][14]
+**function** | [source][7]
```janet
-<function comment>
+(jnj-primitives/init &)
```
-[14]: jnj.janet#L4
+[7]: jnj.janet#L1
## let-j
-**macro** | [source][15]
+**macro** | [source][8]
```janet
(let-j bindings expr)
@@ 253,11 232,11 @@ The default J instance, used by `jnj/j`.
Evaluate let-j `bindings` and `expr` in the default J engine instance (see
`let-j*` for details).
-[15]: jnj.janet#L272
+[8]: jnj.janet#L271
## let-j*
-**macro** | [source][16]
+**macro** | [source][9]
```janet
(let-j* je bindings body)
@@ 285,7 264,7 @@ Here's an example that creates a 4x3 matrix, gets its shape, and then sums
the shape:
```
-> (let-j j-e
+> (let-j* je
> [x ("$" [3 4] [0 1])
> y ("$" x)]
> ('+/ y))
@@ 297,7 276,7 @@ it can also be used to handle datatypes not yet understood by JNJ, like
boxes:
```
-> (let-j je
+> (let-j* je
> [box ("<" "foo")
> arglist (";" box "bar")]
> ("#" arglist))
@@ 308,14 287,14 @@ This same fact makes let-j operations somewhat more efficient than multiple
`eval` calls, as the intermediate values don't need to be copied back into
the J runtime.
-[16]: jnj.janet#L149
+[9]: jnj.janet#L148
-## to-j-value
+## to-j-array
-**function** | [source][17]
+**function** | [source][10]
```janet
-(to-j-value matrix)
+(to-j-array matrix)
```
Turn an arbitrarily nested array/tuple of numbers into a J Array.
@@ 324,5 303,5 @@ NB: This function performs some validation on its input to assert that it can
be transformed into a J Array. So if the data is not already in Janet form,
it might be more efficient to generate it using `jnj/eval`.
-[17]: jnj.janet#L226
+[10]: jnj.janet#L225
@@ 39,8 39,37 @@
See `eval/eval*` and `j/j*` for details.
- All of the above functions have the same basic signature: they take a *verb*
- and 0, 1, or 2 arguments.
+ `jnj` is designed to allow you to use J from within Janet. Thus, it has two
+ main functions:
+
+ - using Janet to drive evaluation of J commands
+ - conversion back and forth between Janet and J datatypes.
+
+ To do so, jnj introduces two main abstract types:
+ - a J Engine instance
+ - a J Array object
+
+ All J computations take place within an instance of the J Engine. For
+ convenience, a default instance is created at import time and available at
+ `jnj/j-engine`. The `eval` and `j` commands both use this default instance,
+ while `eval*` and `j*` allow you to specify your own.
+
+ All of the above functions have the same basic signature (modulo the presence
+ or absence of an engine argument): they take a *verb* and 0, 1, or 2
+ arguments.
+
+ The difference is that `j` and `j*` will evaluate their J command and return
+ native Janet datatypes. `eval` and `eval*`, on the other hand, will return
+ the other abstract type, a *J Array*.
+
+ J Arrays can be inspected for rank, shape, etc., but they can also be passed
+ as arguments to further `eval`/`j` calls. Thus, they're an efficient way to
+ perform more complex procedures, involving multiple calls to the J
+ interpreter, without having to convert data in and out of the J
+ representation. They are also the most efficient and convenient way to create
+ multi-dimensional arrays, as opposed to nesting multiple Janet array/tuples.
+
+ ### `eval`/`j`
The verb can be any J sentence, verb or verb sequence. It can be a symbol or
a string.
@@ 52,10 81,10 @@
((0 1 2 3) (4 5 6 7) (8 9 0 1))
```
- Arguments should be native Janet terms *or* the result of a `jnj/eval` call.
- If they're present, the verb will be applied to them. If there's a single
- argument, it will be evaluated in the form `<VERB> <X>`. If there are two
- arguments, X and Y, they will be evaluated in the form `<X> VERB <Y>`.
+ Arguments should be native Janet terms *or* a J Array. If they're present,
+ the verb will be applied to them. If there's a single argument Y, it will be
+ evaluated in the form `<VERB> <Y>`. If there are two arguments, X and Y, they
+ will be evaluated in the form `<X> VERB <Y>`.
```
repl:4:> (jnj/j "$" [3 4] (range 10))
@@ 68,6 97,40 @@
repl:6:> (jnj/j '$ mat)
(3 4)
```
+
+ In the first example, we evaluate a J sentence using native datatypes and
+ return the result as native datatypes. In the second, we evaluate the same
+ command and return the result as a J Array, which we can then use as an
+ argument in subsequent commands.
+
+ ## Advanced Usage
+
+ ### `let-j`
+
+ The `let-j`/`let-j*` convenience macros provide a simple wrapper around
+ `eval` and `j` which is more expressive and efficient.
+
+ The above example could also be written as:
+
+ ```
+ repl:1> (let-j [mat ("$" [3 4] (range 10))]
+ ('$ mat))
+ (3 4)
+ ```
+
+ ### `to-j-array`
+
+ As noted above, JNJ provides the J Array abstract type as a way to
+ efficiently store J values. J provides an efficient and terse way to
+ construct multi-dimensional arrays; however, if you have some existing Janet
+ data which you want to use as an argument to J, you can convert it:
+
+ ```
+ repl:2:> (to-j-array [[1 1 1][2 2 2][3 3 3]])
+ <jnj/jvalue float [2/9]>
+ repl:3:> (j "+/" _)
+ (6 6 6)
+ ```
````)
(def rpath-fallback "/usr/lib64/j/j64/")