Closed jnorthrup closed 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.
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.
``\
token```` escapes the java legal character limitation of kotlins' origins. i haven't gotten around to tweaking kotlin to just go full unicode but it would be more cool.
kotlin "infix" functions specifier indicates to elide the () around next token parameter which has a generics scope to differentiate overlaps.
you can write a kotlin infix function that will reverse the immediate order of function evaluation so that you can express f before g but the generics pile up so fast you really can't make much headway for currying and concatenative expression syntaxes
[] {} <>
etc. 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.
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.
_+_
=== A binary infix operator, add. Usable as x+y
or _+_(x,y)
!_
=== A unary prefix operator, negate. Usable as !pred
or !_(pred)
_++
=== A unary postfix operator, increment. Usable as i++
or _++(i)
[_]
=== A unary infix (confix?) operator, in this case array creation. Usable as [3]
or [_](3)
to make a 3 element array._[_]
=== A binary infix (confix?) operator, in this case collection lookup. Usable as ary[i]
or _[_](ary,i)
to lookup element i
in collection ary
_[_]=_
=== A trinary infix (confix?) operator, in this case collection assignment. Usable as ary[ i ]=val
or _[_]=_(ary,i,val)
to assign val
to element i
in collection ary
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
<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.
[] === 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]
x=[3].copy(thing) // aa code to make a len 3 array, and fill from 'thing'
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.
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
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.
`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
..
this is a chart with a hint