# Dyalog sessions


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

Import [`Apl`](https://answerdotai.github.io/aplnb/dyalog.html#apl) and
[`AplError`](https://answerdotai.github.io/aplnb/dyalog.html#aplerror)
from `aplnb.dyalog`. Sessions return Dyalog output or JSON-converted
Python values, not bAsedPL arrays. Importing this module does not start
Dyalog or register notebook magics.

Install Dyalog separately. The examples use a local interpreter and run
with `nbdev-test --flags dyalog`. The default test run skips them.

``` python
from fastcore.test import *
```

## Connecting

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L30"
target="_blank" style="float:right; font-size:smaller">source</a>

### start_dyalog

``` python
def start_dyalog(
    dyalog:NoneType=None, # Path to the interpreter binary; `find_dyalog()` result if None
    timeout:int=10, # Socket timeout during the startup handshake, in seconds
):
```

*Spawn a Dyalog interpreter that connects back to us over RIDE; return
`(socket,Popen)`*

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L21"
target="_blank" style="float:right; font-size:smaller">source</a>

### find_dyalog

``` python
def find_dyalog():
```

*Locate the Dyalog interpreter binary*

[`find_dyalog`](https://answerdotai.github.io/aplnb/dyalog.html#find_dyalog)
checks the command path and standard macOS/Linux installation locations.
Pass `dyalog=` to
[`Apl`](https://answerdotai.github.io/aplnb/dyalog.html#apl) to choose
another executable. `timeout` bounds the startup handshake, not
evaluation.

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L64"
target="_blank" style="float:right; font-size:smaller">source</a>

### ride_recv

``` python
def ride_recv(
    sock
):
```

*Receive one RIDE message, JSON-decoded unless it’s a handshake string*

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L49"
target="_blank" style="float:right; font-size:smaller">source</a>

### ride_send

``` python
def ride_send(
    sock, msg
):
```

*Send one RIDE message: a handshake `str`, or a `[cmd,args]` list sent
as JSON*

RIDE uses length-prefixed messages over a local socket.
[`ride_run`](https://answerdotai.github.io/aplnb/dyalog.html#ride_run)
collects session output until Dyalog is ready for another expression.
Interactive and incomplete-input prompts are handled by
[`Apl.run`](https://answerdotai.github.io/aplnb/dyalog.html#apl.run).

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L85"
target="_blank" style="float:right; font-size:smaller">source</a>

### ride_run

``` python
def ride_run(
    sock, code
):
```

*Run APL lines; return `(output,errno)` once the session is ready again*

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L79"
target="_blank" style="float:right; font-size:smaller">source</a>

### AplPrompt

``` python
def AplPrompt(
    ptype
):
```

*A non-ready prompt: 2=⎕ input, 3=incomplete input, 4=⍞ input*

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L73"
target="_blank" style="float:right; font-size:smaller">source</a>

### AplError

``` python
def AplError(
    msg, reset:bool=False
):
```

*A Dyalog diagnostic; `reset` means the interpreter was replaced and
workspace state lost*

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L138"
target="_blank" style="float:right; font-size:smaller">source</a>

### Apl.\_\_exit\_\_

``` python
def __exit__(
    *args
):
```

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L135"
target="_blank" style="float:right; font-size:smaller">source</a>

### Apl.\_\_enter\_\_

``` python
def __enter__():
```

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L123"
target="_blank" style="float:right; font-size:smaller">source</a>

### Apl.close

``` python
def close():
```

*Shut down the interpreter and close the connection*

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L101"
target="_blank" style="float:right; font-size:smaller">source</a>

### Apl

``` python
def Apl(
    dyalog:NoneType=None, timeout:int=10
):
```

*A Dyalog APL session over the RIDE protocol*

## Evaluating APL

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L142"
target="_blank" style="float:right; font-size:smaller">source</a>

### Apl.run

``` python
def run(
    code
):
```

*Run `code`, returning session output; raises
[`AplError`](https://answerdotai.github.io/aplnb/dyalog.html#aplerror)
on APL errors*

`run` returns session output as text. Assignments persist across calls:

``` python
dyalog = Apl()
out = dyalog.run('x←1 2 3\n+/x')
test_eq(out.strip(), '6')
out
```

    '6\n'

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L158"
target="_blank" style="float:right; font-size:smaller">source</a>

### Apl.\_\_call\_\_

``` python
def __call__(
    code
):
```

*Run `code`, returning displayable session output, or None if there is
none*

Calling a session returns
[`AplOut`](https://answerdotai.github.io/aplnb/core.html#aplout), the
same text with notebook display support. A silent assignment returns
`None`:

``` python
test_is(dyalog('quiet←7'), None)
dyalog('2×x')
```

<pre class="aplnb_out sax2">2 4 6</pre>

## Python values

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L164"
target="_blank" style="float:right; font-size:smaller">source</a>

### Apl.pyval

``` python
def pyval(
    expr
):
```

*Evaluate `expr` and return its JSON-converted Python value*

`pyval` uses Dyalog’s JSON conversion. Scalars become Python values and
numeric arrays become lists. This is the interface used by the reference
checker:

``` python
test_eq(dyalog.pyval('+/x'), 6)
matrix = dyalog.pyval('2 3⍴⍳6')
test_eq(matrix, [[1,2,3], [4,5,6]])
matrix
```

    [[1, 2, 3], [4, 5, 6]]

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L177"
target="_blank" style="float:right; font-size:smaller">source</a>

### Apl.\_\_setitem\_\_

``` python
def __setitem__(
    nm, v
):
```

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L174"
target="_blank" style="float:right; font-size:smaller">source</a>

### Apl.\_\_getitem\_\_

``` python
def __getitem__(
    expr
):
```

Square brackets read an expression or assign a JSON-compatible Python
value. Quotes in strings are escaped for APL:

``` python
dyalog['values'] = [3,1,4]
dyalog['message'] = "can't"
test_eq(dyalog['message'], "can't")
test_eq(dyalog['values'], [3,1,4])
dyalog['values']
```

    [3, 1, 4]

------------------------------------------------------------------------

<a
href="https://github.com/answerdotai/aplnb/blob/main/aplnb/dyalog.py#L181"
target="_blank" style="float:right; font-size:smaller">source</a>

### Apl.fn

``` python
def fn(
    code
):
```

*A Python callable applying APL function `code` monadically or
dyadically*

`fn` converts Python arguments through JSON and evaluates the function
expression on each call. One argument supplies `⍵`; two supply `⍺` and
`⍵`:

``` python
mean = dyalog.fn('{(+/⍵)÷≢⍵}')
test_eq(mean([1,2,3]), 2)
add = dyalog.fn('+')
test_eq(add([1,2,3], 10), [11,12,13])
add([1,2,3], 10)
```

    [11, 12, 13]

## Errors and lifetime

Dyalog errors raise this module’s
[`AplError`](https://answerdotai.github.io/aplnb/dyalog.html#aplerror),
which is separate from bAsedPL’s exception. Completed assignments remain
in the session:

``` python
with expect_fail(AplError, contains='DOMAIN ERROR'): dyalog.run('saved←42 ⋄ 1÷0')
test_eq(dyalog['saved'], 42)
dyalog['saved']
```

    42

Interactive `⎕` and `⍞` input is rejected. An incomplete-input prompt
restarts the interpreter and raises
[`AplError`](https://answerdotai.github.io/aplnb/dyalog.html#aplerror)
with `reset=True`; that restart loses the workspace.

Call `close()` when finished, or use a context manager for a bounded
reference check:

``` python
dyalog.close()
with Apl() as reference: total = reference.pyval('+/⍳10')
test_eq(total, 55)
total
```

    55
