00:00 - 21:0021:00 - 00:00

12:04 AM
Anyway to codegolf this down:
x
1 0 3 0 3 0 2
+/x-⍨(⌈\⌊{⌽⌈\⌽⍵})x
6

Specifically hoping to remove the {...⍵} and the second reference to "x"
If you are curious this is the Trapping Rainwater problem: leetcode.com/problems/trapping-rain-water

Same length: `+/x-⍨(⌽⌈\∘⌽⌊∘⌽⌈\)x`

Ninja'd

Or `+/(⌽⌽-⍨⌈\∘⌽⌊∘⌽⌈\)x`.

Guy Steele has a talk on 4 ways to approach that problem, with a view to making it parallel; youtu.be/ftcIcn8AmSY?t=538

Oh, that's `(+/⌽-⍨⌈\∘⌽⌊∘⌽⌈\)x` since we're summing, so -1.

12:11 AM
@TessellatingHeckler how did i not know about this! this was a problem I solved in my first talk that I gave youtu.be/48gV1SNm3WA?t=3285 i had no idea
@TessellatingHeckler thank you so much for pointing me at this
and @Marshall are all of these forks? trains? i have no idea how to visually parse them

@code_report Ugly trains. `+/⌽-⍨⌈\∘⌽⌊∘⌽⌈\ ` is `+/ (⌽ -⍨ (⌈\∘⌽ ⌊∘⌽ ⌈\))`, where the last three functions are the same as `⌈\∘⌽ ⌊ ⌽∘(⌈\)` because composition is weird.

Actually we don't need more `⌽`s than already used, so `(+/⊢-⍨⌈\⌊∘⌽⌈\∘⌽)x`
No double backslashes, just double backticks

:( probably one of my least favorite things about APL is that "3-trains" disable (f g h) being (f (g (h ..)))
as in this case in my original code: ⌽⌈\⌽

Yeah, a train isn't good for monadic chains

For me this is kind of counteracted by 3-trains being one of my favorite things about APL.

12:17 AM
The dfn {+/⍵-⍨(⌈\⍵)⌊⌽⌈\⌽⍵} is easier for me to understand, but that's just me personally

If we had `⍢` (under/dual), `{⌽⌈\⌽⍵}` could be written as `⌈\⍢⌽`
Of course dfn is better to read in most cases

12:37 AM
> For me this is kind of counteracted by 3-trains being one of my favorite things about APL.
+1
I totally agree. Forks (S-combinators) are extremely prevalent and useful
Seems i forgot that I codegolfed this down my self I while back
rainWater ← (⌈\⌊(⌽⌈\∘⌽))+.-⊢
Two forks with the "outer fork" dyadic op being an inner product

⊢+.-⍨⌈\⌊(⌽⌈\∘⌽) works too

@rak1507 oh nice, 1 less char due to too less parens, plus i like ⍨
it is the C-combinator
and the W-combinator in it's dyadic form

⍨ is so useful, I probably use f⍨ more than f on average
Maybe not, but certainly a lot

5 hours later…
5:50 AM
> Are you a Problem Solver (a domain or subject matter expert with problems to solve) or a Programmer (someone who translates those solutions into a computer-executable format)? Problem Solvers benefit from APL's ability to concisely express advanced concepts without getting bogged down with a lot of computerese syntax. Programmers benefit from APL's productivity and brevity. Shorter programs means quicker development time and less code to maintain and debug.
(From Try APL)

6:07 AM
Yeah, I often find myself solving a task faster in APL than in Python.
Except when it comes to system stuff

@Adám the IBM APL2 advert I linked in reply to that talks about APL2 having the ability to share variables between multiple sessions - including over a network - and communicate over a network with one function call; are they ideas which carried over into Dyalog? (not "can you use TCP sockets" but is there a low effort "run this on another machine"?)

@TessellatingHeckler They were talking about shared variables, which Dyalog APL fully supports. That said, we now have isolates which allow you to seamlessly run a function on a different (or the same) machine, just by modifying the function with an operator, similar to `f&`
@rak1507 `⍨` has become so iconic of my APL code that I use it as my icon on abrudz.github.io

6:25 AM
@Adám wow, I've automated Excel through COM many times, and run SQL queries to pull data into Excel, but I've never seen an example like that DDE integration with the Excel formula `=dyalog|myws!sales` that pulls a live variable out of another system so directly
@Adám (incidentally, the ActiveX Control\The Dual Control Tutorial page seems to have all the APL symbols in the code samples replaced by `â`)

@TessellatingHeckler I literally just reported that.

@TessellatingHeckler Btw, here is how to unmangle the text using APL (of course):
```      'UTF-8'⎕UCS⎕UCS ' Value1ââÂ¯1âMSG'
Value1←⊃¯1↑MSG```

6:53 AM
@Adám I've only skimmed the isolates link, so it may be in there, but is there something that needs doing to enable these things? The isolates `¤` and parallel each `∥¨` and in `IÏ` form and `⌶⌶` error as unrecognised if I try them.
sure I've seen Morten Kromberg demonstrate a parallel operator in a video as well

@TessellatingHeckler `)copy isolate` or `⎕CY'isolate'` and then use `ø` and `IÏ` and `⌶⌶`.

@Adám cheers, noted that for future

Does Dyalog APL have any strictly monadic primitive functions?

⍝ ? it only comments the things on the right

Not a function. And even if it were, it is happy with things on the left.

7:09 AM

no, but maybe a loophole. Everything in the language bar looks dyadic

@Bubbler Not a function.

If branch doesn't count, then the answer is no. (Just checked all the docs)

7:10 AM
Yeah.
No matter. I found one that is effectively only monadic.

@Bubbler It means it will reject a given left argument.

Is it on the list of primitive functions here?

Yes.
I mean, it'll reject the argument I give it. It certainly has valid left arguments.

OK, in terms of domain... `○` accepts only integers from ¯12 to 12, `⍎` accepts only namespaces IIRC...

7:16 AM
`⍎` also allows a string left arg.

`⍕` has a pretty specific requirement about left arg too

I have a truly marvellous solution to this challenge which the time is too limited to post.

`⍋⍒` accept only char arrays I think
Good old Fermat joke...
> whatever 3 distinct elements you choose
Ooh, so you have a massive advantage if you can get three distinct primitives to work

7:35 AM
Have to bring kid to school…

oh loooool

7:54 AM
@Adám looking forward to seeing it

8:09 AM
powershell BQN did now runs ~400 VM instructions before breaking on the difference between `null` and `undefined` which JS has and PS hasn't. Ignoring that it gets to ~500 before popping an empty stack, and apparently being out of sync with the JS one.
took me a day or two to port the lines, and was thinking I might be able to get it to run that weekend with luck; that was a month ago, lol.
next stop, give in and find a machine with java on it, so I can run dzaima/bqn compiler and see what that output looks like

8:37 AM
```./cjs.bqn  "(⌈-)4+÷2"
[[0,5,0,2,16,0,0,0,4,17,0,1,0,3,9,16,25],[runtime[0],runtime[1],runtime[3],runtime[7],4,2],[[0,1,0,0]]]```
ah; it depends on having a working runtime to reference.

1 hour later…
9:51 AM
@TessellatingHeckler as a note, despite what i might have said, it does work with java 8
there also is no step-by-step debugging, though it wouldn't be too hard to add

1 hour later…
10:56 AM
Are there any APL Game Engines?

@Razetime I know of a game in APL, but not of an APL Game Engine :)
c.f. KINGDOM

@Razetime Not open source, but the most advanced "game" I know of in APL is Stormwind:

I had no idea Stormwind was a FP simulator ⍥

Here it is running directly off Dyalog on a laptop, controlling a motion platform:

oooo

11:12 AM
OOOO

so, is there any framework
or it has to be custom made

@user872112 Hi frasiyav. If you want to participate here, email me: adam@ with the same domain as www.dyalog.com

@Razetime making a framework is half the fun (certainly most of it for a simulator)

@Razetime Nothing ready, out of the box for stuff like this, no. For simple GUI applications on Windows, you can use a `⎕WC`-based interface. E.g. try `)load arachnid`

@dzaima it will be fun, says the person who wrote their own APL dialect
@Adám will this work on MacOS?

11:16 AM
No, that is based on WinForms, so it doesn't even work with .NET Core (yet).

oh well then
APLP5 is technically a 2D graphics lib
is there anything like that?

For cross platform GUI, the easiest (but not especially easy) would be to use an HTMLRenderer, and ExecuteJavaScript

@Razetime if there was, I wouldn't have made one

@dzaima why?

@Razetime because there already would be one (and probably way better designed than anything i could make)

11:19 AM
Would be cool to make a 2D lib which works in Dyalog

@code_report +1

@code_report @ngn But now we have `⍤` which often works almost as well, and only needs small parens otherwise.
If trains where only atops, then there'd be no way to have an operator that makes forks.

11:53 AM
@Adám well, that's the idea :) no forks
as i've mentioned many times, it would have been much more straightforward to design trains so that removing the final ⍵ from a long expression results in a valid train that does the same.

@ngn I.e. identical to Dyalog's?

f -o g o- h iirc (sorry, no kbd)

@ngn That's not a fork.
What do I think about it? I invented it.

@Adám It is in the monadic case. Not enough in my opinion.

@Adám there you go. if you can invent something like this for the dyadic case - problem solved :)
but first you must understand why this is an important property to have

12:07 PM
@ngn After the first function call there are three live values (two arguments and the result of that function), which I'm pretty sure rules out using ordinary combinators (i.e. not stuffing things in lists) for it.

@Marshall unfortunately, right

Aug 19 at 17:00, by Adám
```      _fk←{(⍺⍶↑⍵)⍹↑⌽⍵} ⋄ fk_←{⍺⍶⍵(⍺⍹⍵)}
10 20(+_fk,fk_×)3 4
13 24 30 80```
(This is for GNU APL, but you get the idea.)

@ngn that's bloat of syntax sugar though! (with the exception of variable lookup, which is more of a dfn problem than a train one)
@ngn also to note is that BQN allows calling monadic functions mid-train by giving a pseudo-left-tine of `·`

@Adám i assume ⍺_ is ⍺⍺, ⍵_ is ⍵⍵, and ↑ is ⊂
so, +_fk, gets evaluated first, ⍺ is 10 20, ⍵ is 3 4, ⍺_ is +, ⍵_ is ,

@ngn `↑` is the same as Dyalogs `↑`

12:21 PM
@dzaima mix? oh..

@dzaima Isn't it Disclose in this case?

@Marshall ah right, it's monadic; yes, it's `⊃`

so ↑⌽⍵ is "last"? it still doesn't make sense to me
ah, i see. my assumption about ⍵ was wrong. it's not 3 4.

@ngn In `_fk`, `↑⍵` is the original right argument (`⍵` from `fk_`) and `↑⌽⍵` is the result from the right tine (`⍺⍹⍵`).

test (dzaima/APL)

12:27 PM
ok, i think i get the idea. fk_ makes a pair and that pair becomes _fk's ⍵
"stuffing things in lists" but so what

@ngn it's ugly

eye of beholder. to me it looks an elegant solution to the problem of dyadic forks without odd-even trains
@dzaima have you got a better one?

@ngn as in, a solution that isn't trains? Writing out the full dfn. it'll be clearer than temporary lists.

@dzaima i assumed _fk and fk_ would be squiggles, so the user wouldn't even be aware of the tmp list
just like those -o and o- in bqn for monadic forks

@ngn so you're proposing adding 2 new builtins to replace trains with a much more ugly syntax
as i said before, i'd much prefer full dfns to these.. things
@ngn also the odd-even thing is never a problem for me
it's either immediately clear, or there are spaces

12:42 PM
@dzaima ..to replace fork-atop trains with much simpler trains

@ngn they would be simpler trains, but also, as a direct consequence, much more useless

@dzaima i can't argue what's a problem for you, but a couple of people above already expressed dissatisfaction with the way trains currently work, and i added my +1

@ngn they expressed dissatisfaction about monadic function usage in APL. BQN solves that. And I'd argue that if you're using >1 monadic function in a train, you probably should write out the full dfn.
trains are an alternate way to express functions, not a replacement for dfns
to me, you're solving a problem that doesn't exist (at least in well-written code), with a solution that disregards the reasoning for why the "problem" is as it is and harms other usages of it

@Adám the way forks work in ngn/apl is remarkably similar - two pseudo-operators (but impl'd in js), one builds a pair and the other one performs all function applications as the fork should

1:07 PM
@dzaima if you don't like it, don't implement it

1:49 PM
CMC [do X without Y]: given a character vector `v` and a character `c`, create a matrix that looks like `c (↑≠⊆⊢) s` but without making use of any APL operators (other than Reduce) and without using ↑↓⊂⊆. (context: it is more or less an exercise on the MDAPL book at a point where the user has a very limited set of tools at its disposal)
tbh I don't even need you to golf your solution. I'm just curious to see what you can come up with... unless you are ngn, then you must golf your solution.

@RGS i assume `v ≡ s`?

woops, yes. In the CMC, `s` and `v` are the same thing. My bad.

i assume padding is also necessary? How about handling multiple consecutive `c`s in `v`?

Oh, by the way, I don't care about what happens if `v` has leading, trailing or consecutive separators `c`. Your solution only has to be equal to `(↑≠⊆⊢)` when `v` has no leading/trailing/consecutive separators
test case: `⋄ c ← '/' ⋄ v ← 'What/is/thissssssssss?' ⋄ c (↑≠⊆⊢) s`

Okay, `((⊃1+(⊣,+)/)×~)c=s` is the classification vector (the trains can all be expanded, of course).

2:06 PM
@RGS hi, i'm ngn's twin brother and i'll try solve this without golfing :)

@ngn Oh hey, welcome! Sure! :D

@ngn You shall be known as ngtwin.

:D
@Marshall then use [ ],← to build a vector of strings
r←(1+⌈/a)⍴,/⍬ ⋄ r[a],←v ⋄ r←1↓r

I have `(' ',s)[1+↑⍸¨(⊂cv)=⍳⌈/cv]` but need to eliminate the `↑` and `¨`.

2:12 PM
mixing seems to be the hardest part

@ngn Hmm, does `←` qualify as an operator in this context? (probably not.)

@Marshall you can assign all you want :)

```⎕io←0
c←'/'⋄v←'What/is/thissssssssss?'
a←((⊃1+(⊣,+)/)×~)c=v
r←(1+⌈/a)⍴,/⍬ ⋄ r[a],←v ⋄ r←1↓r
⎕ml←3
⊃r```

@RGS Sort of an implementation joke since `←` is an overloaded function/operator like Reduce internally in Dyalog.

@ngn it works, but `⎕ml←3` seems suspicious AND in the CMC I said you can't use ↓ ... although it is just to drop the first element, so that is fine. Also, other than ⎕IO the spirit of the challenge is against changing ⎕XX

2:16 PM
↓ oops, i forgot

oh, is the ⎕ml←3 making ⊃ act like ↑? xD

1↓ is 2⊢/
@RGS yes, i couldn't think of anything better

@ngn There is something better. If you can't figure it out, go call your twin brother! He'll help you :)
Btw I'm using a technique that was covered in an APL Cultivation.

⍕⍪r but it has extra whitespace
2⊣/2⊢/⍕⍪r to get rid of it
yay!

Ok
Extra challenge if you want, do not use dyadic f/ because the reader hasn't learned it yet :P
Also, there is a solution without "hacks"

2:25 PM
Basically there: `s{i←⍸m←(⍺=⍵),1⋄h←¯1+⌈/d←i-0,¯1↓i⋄(≢i)h⍴(1+m\h-d)/⍺,⍵}c`
Need to replace the `↓` with a reshape and replace the separators with spaces.

@Marshall Alright, looking forward to the final version.

`s{n←≢i←⍸m←(⍺=⍵),1⋄a←⍺,⍵⋄a[i]←' '⋄h←¯1+⌈/d←i-n⍴0,i⋄n h⍴(1+m\h-d)/a}c`

Skimming through it, it looks vaguely similar to what I did, except my solution is much more verbose :p

hi, i'm ngn. this is my shortest (assuming 2f/ is allowed):
```⎕io←1
2⊣/5⊢/⍕⍪r⊣r[a],←v⊣r←(⌈/a←⊃(⊣,+)/c=v←c,v)⍴0```
shorter: ⎕io←1 ⋄ 6⊣/4⌽⍕⍪r⊣r[a],←c,v⊣r←(⌈/a←⊃(⊣,+)/c=c,v)⍴0 (wrap in {} and replace cv with ⍺⍵ if using them directly is not allowed)

2:46 PM
@ngn `⎕io←1`? You've changed.

@xpqz i don't like ⎕io←1 but 2 bytes are 2 bytes :)
(that's how much longer it would be with ⎕io←0)

3:06 PM
Question about Dyalog: I note that the following is invalid: `1 (⎕←'foo' ⋄ 3) 2`
The statement separator isn't allowed inside parenthesis?

@EliasMårtenson Not yet.

@EliasMårtenson yeah, it is never allowed (yet)

@EliasMårtenson What do you think it should mean?

Well, in this particular case it should be equivalent to `1 (3 ⊣ ⎕←'foo') 2`

a proposed use for it is alternate vector notation - this is how it works in dzaima/APL

3:07 PM
At least that's what I'd expect.

@EliasMårtenson i know some languages use it like that, but JS, Java and Python (the main 3 langs other than APL that i use with any frequency) don't have that

I always assumed that's how Dyalog does it, and I only noticed this because I'm reworking my parser to handle the jot-stuff, and since dyalog supports bare functions, like so: `1 (+) 2`, I was wondring if you could do something like: `1 (⎕←'foo' ⋄ +) 2`

@EliasMårtenson why would the parser need to be changed to support `∘`?

@dzaima Because I need to be able to support bare functions, like (+). Today this is a parse error.

@EliasMårtenson This works though: `1 (⍎'⎕←''foo'' ⋄ +') 2`

3:12 PM
So when I do `(1∘+) 10`, the parser needs to be able to understand the concept of an parenthesed expression yielding something that isn't a value.

@EliasMårtenson It is a function value.

@Adám but a function isn't a value (assuming value ≡ array)

@Adám Yeah, wow :-) I won't support that. In fact, I don't want to support ⍎ at all, at least not in the traditional APL way.

@EliasMårtenson ah, it's just a side-problem, not a direct need of `∘`

@dzaima Well yeah, but without a reworking of the parser the use of ∘ will be limited.
I needed to do this anyway, since in some cases you really need to be able to put parens around a function name to make evaluation clear.

3:18 PM
so you can't do `({10+⍵}⍣{⍺>100})3`, huh. (would be a better example with the right operand of `⍣` being a number, but that doesn't seem to work)

@EliasMårtenson Actually, I think it should be equivalent to `1 ((⎕←'foo') (3)) 2`

@Adám that's obviously a matter of preference. In JS, for example, `(a,b)` evaluates `a` and returns `b`

@dzaima Sure, but I see it as JS's `[a,b]`

@Adám but there's nothing in APL (yet) that ever gives the notion of parentheses being array indicators, and mixing them meaning arrays and nothing is very strange

@dzaima JS's `(a,b)` is more like Dyalog's `a ⋄ b` which indeed returns `b`.
@dzaima Uh, `(1 2)(3 4)`

3:26 PM
@Adám the parentheses there just separate tokens. The vectors are purely stranding, and you don't need to write `((1 2)(3 4))`
@Adám so, why not also have `(a ⋄ b)` return `b`?

@dzaima OK, but in tradfn headers, the right argument being an array (to unpack) is indicated with parens: `Fn(a b c)` even though a normal call would be with `Fn a b c`
@dzaima And `a` would just be for its side effect?

@Adám yep. Just as in `a ⋄ b`
(not saying this is a better use for `(a ⋄ b)`, but it's definitely way more consistent and has more precedent)

That's barely ever needed, unless `a` is an assignment, in which case you can do `{a ⋄ b}⍬`
@dzaima But why use the parens at all?

@Adám well, `({a ⋄ b}⍬)` since we're guaranteed to be in mid-expression if we need `(a ⋄ b)`; and the assignment done by `a` won't be visible outside

But that just gives a confusing order of execution.

3:30 PM
@Adám indeed it does. Again, not saying it's better use than for vector notation, but it's at least consistent

That `x (a ⋄ b) y` should better be written as `a ⋄ x b y` or `x b y ⊣ a`
We have a limited number of grouping symbols, so we need to choose their meanings carefully.
The array notation is actually convenient, while this is just confusing.

@Adám it's convenient, but `(a)` is just completely unrelated to `(a ⋄ b)` and `(a ⋄ b ⋄ c)`

@dzaima No it isn't. It they are exactly as related as `(1)` is to `(1 2 3)`

@Adám which, is, also, just completely unrelated and stupid and awful

@dzaima Yes, so at least we're consistently stupid and awful.

3:34 PM
true. But I'd rather minimize stupidness and awfulness than enforce it

@dzaima Right, but we're out of grouping symbols. We are contemplating adding non-ASCII ones, but that has its own downsides. If we do, then we can stop using stranding.

@Adám right, i agree it's best to use it for vector notation. But again, i was just saying this as an argument for `(a ⋄ b)` being ±`({a ⋄ b}⍬)` being more consistent.

Sure. All agreed then.
If I could start over, I'd probably make JSON valid APL, and add single-quoted characters scalars, and maybe make curly braces be collections of major cells.

is there any reason BQN didn't choose `[]` for vectors? (@Marshall)

I don't understand hot the Dyalog function values work. If you have a series of symbols `a b c d` then depending on which of these symbols are functions, the thing will be parsed differently. But since you can reassign these variables on the fly, how is the parser building an AST of the code? Clearly the parser must know at parse-time whether a symbol represents a function or a value?
So if you have a loop where a variable is reassigned from a value to a function inside the body of the loop, then the entire thing must be reparsed on each loop iteration, no?

3:42 PM
@EliasMårtenson there is no AST

@dzaima OK, but when is the code parsed? Every time it's run?

@EliasMårtenson (at least i assume; things might be quietly cached behind the scenes, but i doubt that)
dzaima/APL parses code live while executing. A line to execute is given to the executer just as a token list
@dzaima (you can see that happening)

@dzaima Interesting. Does that mean that Dyalog doesn't have closures?
I'm pretty sure someone said it does have it.

@EliasMårtenson it doesn't (mostly, afaik), but that's completely unrelated. dzaima/APL has closures

@dzaima But to ensure you bind the correct values to a closure you need to know which symbols in the closed-over function is being referenced.
But if you don't parse until execution you won't know what values needs to be stored in the closure.

3:49 PM
@EliasMårtenson dzaima/APL stores variables in a hashmap, which can dynamically add new variables
(and dyalog needs to handle that too - see `{x ⊣ ⍎'x←4'}⍬`)

@dzaima Sure, but when you return a closure, you need to know which of the variables you want to preserve. Unless you store the entire hashmap in the closure but that's very wasteful.

@EliasMårtenson that's what i do. And dyalog doesn't have closures, so it doesn't need to worry about that

@dzaima Right. Without closures it's of course much easier.

and if there's an `⍎` in the function, you have no choice but to keep all the variables of all scopes above

@dzaima Yes, which is why I don't support that. Well, I might, but if I do, the evaluation of ⍎ will happen in the null environment (an environment which does not have access to the local variables)

3:52 PM
@EliasMårtenson "very wasteful" - it wastes some RAM, but other than that it should be harmless (at least in how i've implemented it; Also, how often would >0.1% of your ram usage be closures anyways?)

Or rather, will not have access to the local variables outside of the local environment.
@dzaima True. I wastes RAM. But in the worst case scenario you're holding on to a lot of data that would otherwise be GC'ed. Perhaps it's not really an issue in practice. I mean, after all, KAP suffers from the same problem too (because I haven't written the code that extracts only the relevant variables to the closure)
By the way, what language is Dyalog implemented in? (this is just to satify my curiosity)

@EliasMårtenson i believe C mostly
wiki - C, C++, APL; later on, "is implemented primarily in C"

4:19 PM
@EliasMårtenson it's tokenized at "fix" time (understand: compile time) and the sequence of tokens is interpreted at runtime
@EliasMårtenson closures - yes in the sense that a dfn sees and can modify the variables in its enclosing dfns

@EliasMårtenson and since a closure'd function could modify variables of its parent closures (which other functions can see), you can't flatten the variables either

4:42 PM
@EliasMårtenson I considered this for BQN (and of course it can still be added). I rarely feel like I want it, and it seems likely to lead to confusing code, so I currently don't think it's worth it.
@dzaima I'm still planning on using `[]` for high-rank arrays. It's not syntactically much better than `>⟨⟩`, but it's cleaner in cases like destructuring assignment.
@EliasMårtenson You can get a function to survive past the end of its parent function, for example using a namespace, but the parent function's scope is freed once the function finishes, so closures don't work.

@Marshall right, but why not then swap `[]` and `⟨⟩`?

@dzaima Because I find associating `⟨⟩` with lists and `[]` with matrices or higher-rank arrays more obvious.

@Marshall huh.

2 hours later…
6:28 PM
@dzaima I tried Java 8 because ibm-java80 is what apt found, and it did work; how did you bootstrap and test it from nothing to working?

@TessellatingHeckler bootstrap what?
to run dzaima/BQN, all you should need to do is `./build` and then `./REPL` to get a REPL

@dzaima bootstrap coding it

@TessellatingHeckler ah, how I did; misread

I'd believe if you just wrote it once and it worked first time :D

i started with dzaima/APLs source, added new builtins, removed old builtins, added compiler, and once that worked, removed the runtime parser
the original 1st working version of dzaima/APL was tiny (and written in Processing), it really didn't take much to get it running. Getting that to where dzaima/APL is now was continual adding/replacement of things

6:39 PM
ah I forgot it was based on dzaima/APL;

@TessellatingHeckler yeah; writing from scratch would be somewhat more complicated since a compiler is way more complicated that dzaima/APLs runtime parser

7:17 PM
(in general though, you probably want to start with a simple thing that runs `2+2` successfully, and slowly add more and more features)

7:31 PM
@dzaima If I was building a parser from scratch I could slowly add more, but porting the JavaScript means there's a big jump between "cannot run the self-hosting BQN compiler" and "can run it". Running compiled byte code for 2+2 worked weeks ago, and compiled bytecode which depends on the `runtime[0]` is too advanced, I can't build the runtime yet.

@TessellatingHeckler right. You probably want to write some intermediate tests for separate things - operators, trains, closures, etc

@dzaima did you see my source dump (each line has the JS it came from as a comment at the end), so it's not like it will gradually get operator support, then gradually get trains support

@TessellatingHeckler you say that `2+2` works. Does `{𝕩‿𝕩}{𝔽𝔽𝕩}1` work? Does `f←{x←1⋄{𝕩‿x}} ⋄ F 4` work?

@dzaima "5+5" as source code doesn't work, hand-compiled byte code for 5+5 where I put an addition function like `run (&\$arr 0,1,0,0,0,1,17,25 8) (&\$arr @({param(\$x,\$y)\$x+\$y}, 5) 2) @(@(&\$arr 0,1,0,0 4))` works and executes 5+5
hand compiling more simple cases - more bytecode, more blocks, is straightforward, hand compiling the functions in the middle for more complex cases, is not something I've worked out

@TessellatingHeckler right, you're still at the phase where you need to manually feed bytecode to get things. That's why those two tests of mine don't use any built-ins, so only pure bytecode evaluation is tested

7:39 PM
@TessellatingHeckler It shouldn't be too hard to hack cjs.bqn into the form you want. List formation is in `L` for example.

you can do `./cjs.bqn "{𝕩‿𝕩}{𝔽𝔽𝕩}1"` to generate the bytecode for a single test. it's in JS format, but transpiling that should be easy enough
and you definitely want to write a (temporary) script to convert that output to something you can feed to your interpreter

@dzaima "Does {𝕩‿𝕩}{𝔽𝔽𝕩}1 work?" it returns (1,1),(1,1) which seems the same as the JS code returns

@TessellatingHeckler That's working.

@TessellatingHeckler so it works. That signals that quite a few bytecode operations work correctly, plus at least partial block execution

@Marshall not too hard for you :P it's the bit where it embedds "runtime[5]" that I can't use yet

7:47 PM
@TessellatingHeckler you can get quite far without needing any working builtins
once the vm without any runtime works perfectly, adding the initial array and calling the runtime & compiler should just work
(mind you, it could be quite slow)
another test: `a‿b‿c‿d←1‿2‿3‿4 ⋄ d‿c‿b‿a`

@dzaima " Does f←{x←1⋄{𝕩‿x}} ⋄ F 4 work?" gets me (4,1)

@TessellatingHeckler so closures also appear to work, which is nice
`F←{x←𝕩⋄{𝕩‿x}} ⋄ x←999 ⋄ a←F 1 ⋄ b←F 2 ⋄ (A 10)‿(B 20)` is a more thorough closure test

@dzaima this comes out as 4,3,2,1 which seems ok

@TessellatingHeckler yep; so strand assignment also works
(running out of things i'm assuming could be broken)

Are trains tested yet?

8:02 PM
modified assignment (extremely weird due to no builtins, but it works) - `a‿b‿c←1‿2‿3 ⋄ a‿b‿c{𝕩‿8‿9}↩7 ⋄ a‿b‿c`

Could also check `2+a←1` to see if assignment passes through properly.

@Marshall `2‿a‿(a←1)` if no `+` is available
@Marshall `4({𝕩‿6}{1‿𝕨‿𝕩}{3‿𝕨‿𝕩}{2‿𝕨‿𝕩})5` and `({𝕩‿6}{1‿𝕩}{3‿𝕨‿𝕩}{2‿𝕩})5` should be good for testing those
i don't think it's possible to test for `{(𝕨÷⊢)𝕩}5` without a function distinguishing monadic and dyadic calls (`÷` there) though

@dzaima now this might be breaking (or I might have the bytecode wrong); ooh

@TessellatingHeckler so closures aren't actually working (presumably)
but at least the problem is reduced from the entire runtime to a single line of code

Try `F←{x←𝕩⋄{𝕩‿x}} ⋄ x←999 ⋄ a←F 1 ⋄ A 10` next I guess.

8:09 PM
@dzaima this seems to work, 7,8,9

@TessellatingHeckler so that should clear assignment from any problems

@dzaima actually, doing it again from scratch, it does run; gives me (10,1),(20,2)

@TessellatingHeckler so closures are working?

@Marshall (10,1) looks okay

@dzaima actually that's wrong. should be `(a←1)‿a`, though just `a←1` (or better, `a‿b←1‿2`) is enough for testing whether the result is correct
another closure test (plus modified assignment) - `F←{x←𝕩⋄{x‿(x↩𝕩)}} ⋄ x←999 ⋄ a←F 1 ⋄ b←F 2 ⋄ (A 10)‿(B 20)‿(A 30)‿(B 40)`
another thing that should be tested is LEB parsing, but that's hard to test

8:24 PM
"(a←1)‿a" gives me 1,1 which looks like it passes through

@TessellatingHeckler What does `\$myinvocation.BoundParameters.ContainsKey('w')` do if `w` is `null`? The Javascript version relies on `has(w)` being false if `w` is passed as an argument but equal to `undefined`.
Similar concerns with `if(\$f)` in case 10/19. This test needs to be true exactly when `\$f` isn't null.

@Marshall that is something I've tripped over since pasting the linked code; if call() calls f(x,w) then BoundParameters says "you passed 'w' in" regardless of whether w has a value or is null. It can't distinguish "w was defined as null" from "w was undefined and not passed in".

@TessellatingHeckler so you want to have two proper separate values for null and undefined

I've tried to modify call() to say `{&\$f \$x \$w}else{&\$f \$x}` but that might not be enough, I think that change needs to be pervasive

(wait, does `call` even need to separate the two cases? `w` being null (if null ≡ `·`) and not given should be the same)

8:33 PM
@TessellatingHeckler I think you should change those BoundParameters checks to is-null checks, and always pass three arguments to `call`.
@dzaima `·` is `undefined`; `null` indicates an uninitialized variable.

@Marshall i though PS didn't have `undefined`?

@dzaima I think call needs to separate the cases because it hits one of the core functions (monadic equals) and doing dyadic equals and failing, because instead of getting undefined w, it gets null w

@TessellatingHeckler `call` should act the same if given a `null` w and undefined w. The easiest way to achieve this is to always call `call` with the `null` for w when you're calling monadically

@dzaima In PS they're both `null`. I'm not sure which two cases in `call` you meant now: seems there's only a test for `x` not being present.

@dzaima but the called function should act differently given a value of null, or an undefined w. From inside the function JS can look for null vs undefined, but I cannot tell which case was which, both cases bind w to null and look the same, and trigger a dyadic euqals instead of a monadic one

8:37 PM
@Marshall yeah, i misunderstood it; there are 2 cases - w present and not present
@TessellatingHeckler `call` in JS should never get a `null` argument
`null` in JS only ever means an unset variable

Exactly.

In the instruction code, instructions 5 and 6 are:
\$s.push((&\$call \$f \$x ))}
\$s.push((&\$call \$f \$x \$w))}

I can tell there that w has or has not been passed
inside call() I now (not showin in linked code) have:

if (\$myinvocation.BoundParameters.ContainsKey('w')) {&\$f \$x \$w}else{&\$f \$x}

@TessellatingHeckler `\$s.push((&\$call \$f \$x))}` and `\$s.push((&\$call \$f \$x null))}` (assuming that's the syntax to do that) should be the same

@TessellatingHeckler Since in PS not passing `w` is different from passing any particular value, you should never not pass `w`. In Javascript it's the same as passing `undefined`, so I used that as a shortcut.

@dzaima they should be the same? surely not?
has(w) should be false for the first and true for the second?

8:42 PM
@TessellatingHeckler it should be false for both
See `{𝕨-𝕩}5` in BQN - `𝕨` is `·` (null in your impl, `undefined` in JS), so should call `-` monadically
(fwiw, in my impl `·` is a nothing, and i use `null` for unset variable slots)

@Marshall e.g. in the core function "equals" is `(x,w) => has(w)?+(x===w):x.sh?x.sh.length:0`. If I test `\$null -eq \$w` then I can't tell a difference between it being passed with a value of null, and it being not passed, because it will implicitly be bound to null. Are you saying it will never genuinely have a null value, but you can't test for that easily in JS?

@TessellatingHeckler `w` will sometimes be defined, but be null, which should be the same as it not existing and should do a monadic call

@dzaima that seems too easy

@TessellatingHeckler BQN is designed to be easy to implement…

@dzaima that invokes `FN2O`, but, evidently, calls `-` monadically, because the result is `¯5`

8:57 PM
early on, some of the setup code, not sure exactly which bit, does `(@(\$sv)+\$v)` and \$v is undefined and the environment everafter has [foo,foo,undefined,foo,null,null,null,...]
in state / instruction 21 which reads a variable out of the environment, there is an assertion in JS `assert(v!==null)` which is fine with that `undefined`
I get a null from the undefined variable, and the assertion doesn't like it
this is where I get ~400 instructions into building the runtime, and that's what trips it up

00:00 - 21:0021:00 - 00:00