Skip to content

Jacob-Lockwood/j-avascript

Repository files navigation

J-avaScript

Write JavaScript tacitly with J-like trains

This project is heavily inspired by @cyoce's J-uby project, which extends Ruby's Symbol objects with operator overloads allowing the composition of tacit functions. I created J-avaScript partly because I know JavaScript much better than I know Ruby, and partly because I thought it would be funny to do the J- thing for a language whose name already starts with J.

In JavaScript, operators cannot be overloaded, and functions cannot be referenced as concisely as using Symbols is in Ruby, so I opted to use a tagged-template based syntax which is parsed from a string to a function. This also allows J-avaScript to support fork-trains, which are very useful and fun.

Something which may be surprising to those familiar with J/APL is that J-S's trains execute from left-to-right, rather than right-to-left. This is because JS itself runs left-to-right, and makes sense if you consider that in J, writing x F y means you are using x as the argument to F in order to modify y, while in JS writing x.F(y) means you are using y as the argument to F in order to modify x.

J-S optimizes the referencing of functions to be very concise. Writing the word split is equivalent to writing (x,y)=>x.split(y), writing the operator + is equivalent to writing (x,y)=>x+y, writing the word length is equivalent to writing (x)=>x.length, and so on. Constants and anonymous functions can be referenced using the template-interpolation ${val}. If the value is a constant, it is treated how a constant-function would be treated in trains in J.

Here's an outline of J-S's components for tacit composition:

conjunctions
    F#G     x.F(G)
    v#F     v.F(x)
    F##v    x.F(...v)
    F@G     F(x).G(F(y))

adverbs
    /.F     x.reduce(F)
    \.F     x."scan"(F)
    *.F     x.map(F1)
    '.F     x.map(F2)
    ~.F     x.F(x) or y.F(x)

extra ops
    x[y     x
    x]y     y
    x\y     floor(x/y)
    x,y     [x, y]
    x'y     range(x)

other syntax
    F;G     pipe (think [: in J)
    F G     hook
    F G H   fork

And here are some examples of functions written first in plain JS, and then with their tacit J-S counterparts, sometimes with multiple options of how to write the same expression.

As you can see, J-S often makes the code much shorter, but in some instances can actually result in longer code, so if you're using this library for code-golf purposes, keep in mind what scenarios tend to be shorter when written explicitly rather than tacitly.

x=>x+1
J`+#${1}`
J`${1}+]`
J`+${1}`

x=>x.reduce((a,c)=>a+c)/x.length
J`(reduce#+)/length`
J`/.+/length`

x=>"Hello, World!".indexOf(x)
J`${"Hello, World!"}#indexOf`
J`${"Hello, World!"}indexOf]`

x=>x.map(z=>z**z).reduce((a,c)=>c+a)
x=>x.map(z=>t+=z**z,t=0)&&t
J`*.~.**;/.+`

(x,y)=>(x+y)*(x-y)
J`+*-`

x=>x.map(v=>v.toString(2).replace(/0/g,"").length)
J`*.(toString#${2};replace##${[/0/g,""]};length)`

x=>x.map(v=>v.toString(2).split(1).length)
J`*.(toString${2}split${1};length)`
// Notice how constants are treated in trains.

x=>x.slice(0,2)+"..."+x.slice(-2)
J`slice##${[0,2]}+${"..."}+slice#${-2}`

About this repo

This repo contains the Vite and SolidJS website deployed at j-avascript.netlify.app. The source code for actual J-avaScript interpreter is in the file /src/j-avascript.ts, if you need just that. I may turn this into a monorepo and publish the interpreter on NPM.

About

Write JavaScript tacitly with a J-like syntax

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published