~subsetpark/jnj

d49462b5e7045aada32912d42341673328edbee9 — Zach Smith 2 months ago 20af4e4
Update docs
3 files changed, 161 insertions(+), 119 deletions(-)

M README.md
M jnj.janet
M project.janet
M README.md => README.md +89 -110
@@ 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


M jnj.janet => jnj.janet +3 -3
@@ 162,7 162,7 @@
  the shape:

  ```
  > (let-j j-e
  > (let-j* je
  >  [x ("$" [3 4] [0 1])
  >   y ("$" x)]
  >   ('+/ y))


@@ 174,7 174,7 @@
  boxes:

  ```
  > (let-j je
  > (let-j* je
  >  [box ("<" "foo")
  >   arglist (";" box "bar")]
  >   ("#" arglist))


@@ 215,7 215,7 @@
  (let [res (eval* je verb ;args)]
    (from-j-value res)))

(defn to-j-value
(defn to-j-array
  ```
  Turn an arbitrarily nested array/tuple of numbers into a J Array.


M project.janet => project.janet +69 -6
@@ 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/")