Friday, September 22, 2017

Log 092217

Right, so I worked on a foreign function interface (FFI) by employing C++ macros and bound the Commonmark C library in Egel. It took me a few days to subsequently implement transforms.

Types, those were half the reason I worked slowly. I am not sure I need them or miss them.

Meanwhile, I am trying to convince people on #proglangdesign that programming language designers need to be punished for their crimes. I pointed out that Anton Chigurh is a good artist's impression of a language designer: "Some sociopath killer who sees himself as a pure tool of reason, and inflicts world-wide suffering while never being aware of all the pain because of his own strange psychopathy."

Ah well. Still not sure I can do anything useful with these Commonmark bindings.

Thursday, September 14, 2017

Log 091417

<spruit11> the Self, as epitomized by 'this' in several misconstrued languages, 
           cannot exist as a pure presense vis-a-vis the denial of 
           the Other. an OO language which doesn't expose a 'that' as 
           its necessary, to be elocated, counterpoint is, therefore, a 
           metaphysical paradox reflecting the categorical mistakes of
           the language designer.
<spruit11> or, Stroustrup is a turd.

Rethinking OO and operators.

Sunday, September 10, 2017

That Constant Thing

I completely reversed my position with regard to the preceding post. I need some form of FFI but I am not going to do constant support. First, let's look at the problem.

Say, I'll allow native constants in Egel with a 'const' construct.

    const FIVE = 5

Conventionally, this would introduce a syntactic equivalence; the symbol 'FIVE' and the value '5' should be interchangeable in source code. The difference between such a construct and a normally named abstraction is small but significant. In expressions, you hardly notice.

    FIVE + 5

That should evaluate to '10'.

In a pattern match, the difference becomes apparent.

    [ FIVE -> "five" ] 5

Conventionally, you don't match against the symbol 'FIVE' here but against the value '5'; i.e., the expression above reduces to "five".

I looked at other languages. C/C++ support constants in header files and C++ has a notion of const expressions. Java has static final variables. Haskell doesn't have a notion of syntactic equivalence. Python defaults to using variables. Lisp has constant expressions, no doubt in the form of a macro.

In the end, none of them really handle syntactic equivalence well. And there's a reason for that.

There are a number of manners to support this construct. Through a preprocessor, through a macro extension, through syntactic sugar, or make it native to the language. For Egel, a preprocessor would be nice, macros would be nice, syntactic sugar would be the easiest, native to the language would mean a small overhaul.

Syntactic sugar is easy but conflicts with another goal I have, I want to be able to use source files and object files (which are C++ compiled dynamic libraries) interchangeably. In the future, it should be possible to compile any source file to an object file and load it. But byte code doesn't carry, and probably shouldn't carry, syntactic information -or some notion of the AST- so substitution on the source code can't be implemented.

Which would imply making constants native to the language but, at the same time, it's hard to implement a notion of syntactic equivalence if all you have are C++ defined combinators. Making constants fully native to the language would mostly imply overhauling the byte code or byte code generation. I.e., since the difference with normal combinators is in the pattern match, the simplest solution would be to generate code like "match against the definition of this symbol, not its name." I am not terribly comfortable with such a change at the moment.

A preprocessor or macro support would be nice but similar to a syntactic sugar extension conflicts with the goal of interchangeable dynamic modules.

And there you have it. Roughly one can support constant definitions at the text, AST, or code level, where code is the most portable but hardly anyone implements a scheme such that you can reason back from generated code to a syntactic equivalence.

But the problem I still have is in binding with C/C++ modules which normally introduce large numbers of constants through macros or enumerations. Some form of FFI support or C++ code generation would greatly diminish efforts needed.

Maybe C++ macros or templates could fix this? I should look into that.

Thursday, September 7, 2017

Log 090717

Small stuff. For some reason not completely clear to me I decided that after implementing some Rosetta code examples it would be a nice idea to do some documentation tooling. Commonmark -a small and fast system for Markdown- seems the way to go. I am busy implementing an Egel wrapper around that, but I am somewhat baffled by the hoops I need to jump through to get it all done.

Lack of a foreign function interface (FFI) and lack of constants, or enumerations, are hurdles to take.

The first one, lack of an FFI, I don't want to tackle. My own small experiments with FFI in the Hi language lead me to the conviction that either you support the full C type system, probably including support for parsing header files, or your solution isn't worth it. And even when you got that covered you'll still need glue packages for interfacing with C++.

My solution: no FFI. "Write the glue in C++!" is the adagium for the moment.

The second one, lack of constants/enumerations, I think I want to tackle but I am not sure how yet. There are two well-known solutions: implement a preprocessor or support constants natively in the language. The first solution has as an advantage that that would also bring conditional compilation into the system, the second solution I didn't think fully through yet. Why did C++ implement the 'const' directive? For large constants? Supporting a directive would probably give an advantage that I can mark (large) terms which don't need to be reduced. But at the same time I want to introduce names for terms to insert and pattern match against.

I implemented the start of a String library and noted that I needed to refactor the module system. With the side notes that in the first case a C FFI wouldn't have helped since I was binding C++ Unicode string objects, and in the latter case modules now wrap transforms but need to reflect the conceptual model of Egel constructs properly.

Sunday, August 27, 2017

APL's iota

So it's trivial to implement an APL-like iota combinator.

>> def iota = [ 0 -> 0 | N -> (iota (N-1)) N ]
>> iota 5
(0 1 2 3 4 5)

I subsequently set out to see if I could define factorial in an APL manner. The definition should be something like below.

>> def fac = mult @ map [X -> X + 1] @ iota

But the problem is Egel can't really pattern match readily against a variadic sized array. Take a variadic number of arguments, no problem; match against an n-adic construct, if n is known - sure; match against variadic array, no can do.

So, I either implement car/cdr like deconstruction combinators or I extend the pattern matching features. Where the new snag is that my bytecode doesn't support variadic pattern matching..

Log 082717

I took a small break. Most stuff works now but I hit a small snag which developed after changing the operational semantics of constant application.

>> def f = 1 2
>> f
(1 2)
>> def g = 1
>> def f = g 2
>> f

The first definition of f works according to the change in semantics but the second one still optimises constant applications away. I can easily change this but also at a potentially huge performance cost.  *I fixed this.*

I got the dual of variadic application working though, which is nice.

>> def app = [ 0 -> nil |  N -> (app (N-1)) N ]
>> app 3
(System.nil 1 2 3)