cliffclick / aa

Cliff Click Language Hacking
Apache License 2.0
272 stars 21 forks source link

operator overloads #7

Closed jnorthrup closed 2 years ago

jnorthrup commented 2 years ago

`lo

i think you have a foundation to close a gap on three fascinating orthoganol programming enablements that will provide an exponent of programming liberties

essentially, the above looks like to me like the tool for any given programming language to most versatiley transcribe expression pasted in from diverse sources and some glue code to patch up the evaluation semantics to match.

a really long time ago the boost c++ team adopted boost spirit to crib a c++ orienttion of weak features in the area above to build parsers in an EBNF look-alike c++ grammar.

having those three things above would enable a snowballing library transcription process from diverse language sources under one join-point.

what is unclear at this time about aa

image

..

this is a chart with a hint

image

cliffclick commented 2 years ago

Probably straightforward to extend the parser oper syntax to allow new opers. Would also need a way to specify precedence and uni/bin/trin ops. The actual parsing of such is already implemented (table lookup of precedence ops, binary-vs-pre-vs-post, etc). No promises but should be straightforward enough.

jnorthrup commented 2 years ago

in java/c98/c++ terms i look at oper precedence as an enum however numerous.

this was forwarded for which I would say my preferences are away from sexp personally https://www.swi-prolog.org/pldoc/doc_for?object=op/3

kotlin has done a few things right that i haven't seen done since the usenix es shell.

inherently json, sgml i.e. some html and xml, and graph notations could all be copmiled with overloads instead of parsers.

this example was from textbook https://gist.github.com/jnorthrup/60d1465c29c85b183d502d521a7b9022#file-implication-kt-L145 just to see how far the kotlin legal syntax could be pushed.

im aware of auto-grad techniques that would again benefit greatly from overloads to replace parsers and precompilers to arrive at a function abstraction into self normalizable concepts. the entry point of thier usecases is matrix math, in languages that are not transparent as such.

cliffclick commented 2 years ago

Currently thinking of using a specialized name layout to describe the operators. The '_' character denoting where an expression can go when the operator is used inline, and otherwise the full operator name is used when the operator is being used as a function name. Note that expressions are the full grammar, so nested infix/confix operators are supported.

Ok to use any characters from the operator set - which excludes at least _()"'\ and probably :0-9 as leading operator characters, and probably several others. Includes at least <>!@#$%^&*+-={}[]|$.

Cliff

jnorthrup commented 2 years ago

<rant typesystem> I can't guess the type inference features of the above or any primitive/Struct borders from what i have read to date, but I currently have in kotlin something which is an unintended idiom of the language's freedom I can reason with using Kotlin's java+typealias type system, heavy emphasis on typealiasing.

what i have come up with in Kotlin to enable terseness and free-work from the compiler is a typealias hierarchy with delegations that are more interchangable than java and preserve type safety even if sometimes the depth of aliasing is beyond intellij/lint grasp, in those cases you just add a strategic cast. many years ago i went with Java interface a<left<super a>,right<? extends left> > silliness and had something cool, but unable to achieve type aliasing and promotion/demotion to a usable degree. </rant>

so via operators and type delegates i do currently have in production

val x="banana"
val y=x[1,3,5,0,2,4]
assert(y==_l['a','a','a',b','n','n'])

as this applies to a columnar csv reader which is ultimately a Pair typealias that has a blackboard shaped column header delegation this allows val c=readCsv(file) val c1=c["open","close"] //unary operator on T[]:T=String done as varargs reorders with only selected columns through delegation assumptions on the first parsed row val c2=c[1,0] //unary operator on int[] '' val t=3 t2 4 // pair infix interface version of Pair val z=-(t)[1,0] //unary minus converts to list, enabling unary operator reindexing

and my primary value add construct is deferred permutable vectors(Vect0r) val vec=x.size t2 {i:Int->x[i]} //immutable array-shaped hyperspace as Pair(Pai2) typealias

thereafter operations of vec.map(function xyz) written by inline capture as {i:Int->xyz(x[i])} become fully deferred and show up quite late in profiling and generally very far from the point defined particularly when there is cached IO. im assuming the confix ops you showed could support the "banana" reordering usecase.

For promotion _t2_ infix from Pai2(Pair) to Tripl3(Triple) by _t3_ it is a delegated overload on Pai2 type

val c=1 t2 2 t2 3 // (1,(2,3) -- counter-intuitive but a feature of right to left eval
val d= (1 t2 2) t2 3 // ((1,2),3) 
val e=1 t2 2 t3 3 // (1,2,3) 

what i am doing by hand is for c, the csv columnar rowset, is Any? t2 { -> CoroutineContext} this is provably flexible without using coroutines to allow routed specific state into table formulas, making for blackboard spreadsheet functionality, thus typically stowing column info but sometimes unbounded data here. it is presumed that the CoroutineContext function gets clipped in the inliner eventually when use doesn't occur inside a loop. the specific data structure, and nothing to do with the coroutines API per se, is a hierarchically structured enum at compile time so you will have a const key if you use any part of the CoroutineContext, irrespective of whether the Context is sourced from the parent context or simply being held as a quirky Set with const keys

issue #13 goes into being able to apply so much operator overloading magic or none at all to view a compiler construct as its graph, at an even deeper level of compiler state than the expression level language syntax and operators for humans, per se. the barrier between source code, compilation graph, and IR processing is a voluntary set of boundaries to help large teams of compiler maintainers to conceptualize and visualize the previous generation of language enablements, so the question/proposal of #13 is to bring a flat compiler state notation into view of the programmer, without syntax, be it compiler-irrelevant metamodel annotation fluff or type/classifier/pragma state under one roof. macros and IR and source code in an unsightly collider.

jnorthrup commented 2 years ago

[] === A unary infix (confix?) operator, in this case array creation. Usable as [3] or [](3) to make a 3 element array.

kotlin does something very good with Array<T>(size:Int,(Int)->T) which shows up when porting from java as concise for-loop collapse whether by intellij or manual coercion of the loop that only fills an array.

instead of

var x =Array<thingType>(3) // not legal because of jvm generic arrays but example here 
for(n in 0 until 3){x[n]=thing[n]}

you get var x=Array(3){thing[it]} or var x=Array(3,thing::get)

it also forbids index operators in declarations unless they are overridden functions such as _a[1,2,3]

cliffclick commented 2 years ago

x=[3].copy(thing) // aa code to make a len 3 array, and fill from 'thing'

cliffclick commented 2 years ago

im assuming the confix ops you showed could support the "banana" reordering usecase.

Unrelated to ops; 'aa' does aggressive C-like 'constexpr' evaluation. Constant valued expressions pushed through constant-length loops are all constant folded. So yeah, the "banana" case is handled, but its not (really) related to the operators.

jnorthrup commented 2 years ago

the reordering is

typealias Vect0r<reified T> = Pai2<Int, ((Int) -> T)>

@JvmName("vlike_Vect0r_getVarargInt")
operator fun <T> Vect0r<T>.get(vararg index: Int) = get(index)

@JvmName("vlike_Vect0r_getIntArray")
operator fun <T> Vect0r<T>.get(index: IntArray) =
    (index.size) t2 { ix:Int -> second(index[ix]) } //a pair

mirrored by image

it's possible that charsequence and the assertion comparison need promotion to List first in the example, technically.

the constant length loop you mention would be the reification, typically for effects. this would be a chunk of lambda capture until so looped.

jnorthrup commented 2 years ago

21 makes more sense to me.