Saturday, September 14, 2013

Functional Program for compilers(language processors)

Compiler/Interpreter has been used since assembler/FORTRAN era.
It was one of most powerful software.
But the behavior is rather different from typical programs which takes a limited pattern of data structure as input and return  also limited pattern of data.
for instance typical method/function takes some data like int, and returns another object or data like if you put a coin to a vendor machine and push selection button, you get candy etc. quite mechanical.
On the other hand compiler can take million of line code code and generate something which can perform very complex thing as output, this is more like something only human can do.

the interesting nature is in compiler,  in the tree like data structure, each node is mapped to a closure recursively and the top node behavior can be constructed from these behaviors.
So this is quite good fit for functional programming language.
Often there are a but none standard interpretation between compiler and interpreter from none computer science oriented people.
for latter, interpreter mean tree traversing program, i.e, it take program(tree) as input and return some result.
The compiler mean it return some closure(function) from input program(tree), and no specific result is not yet given. the result can be only available by applying the function some context.
so if in compiler, we don't have to traverse program many times for different program inputs. just compile once and get function, and the different values can be obtained by just applying the function with different input values. in this function evaluation, no tree node data used.

for instance, a very simple compiler program will be as following:
typedef Object Code(RContext ctx);

class AddNode implements INode {
  INode node1;
  INode node2;

  Code compile(Context ctx) {
    Code c1 = node1.compile(ctx);
    Code c2 = node2.compile(ctx)
    return (RContext rctx)=>(add(c1(rctx), c2(rctx)));


var addNode = new AddNode(new IntNode(1), new IntNode(2));
Context ctx = new Context();
Code code = addNode.compile(ctx);

RContext rctx = new RContext();
var v1 = code(ctx);
 In fact, Dart does not support overloading, so this will use overriding of methods(even if it supports overloading, this  overriding approach is better though).
Subsequently the metaphor is changed in object oriented way, i.e, a node object has a compile method which  generates a compiled closure.
 This  is actually a good example of usefulness of mixing  two object oriented approach and functional approach.(although it became a matter of course nowadays for javascript programmers, but early days in 80's, many people were not much interested in such impure approach. Probably their target application(e.g, 5th generation Hardware) were different. but from pragmatic programming point of view, this should have been more emphasized. Some Lisp dialects were actually advocated these things, but Lisp had too poor syntax to be accepted by normal people, so there were no impact for general programmers.

------------
There were  bit of digression,  but bottom line is Dart will assist to write such compiler like application in wide range.
These are the reason to have appropriate syntax to express a conceptual idea directly in a language without any technical transformation(see anonymous object in Java). I remember Gosling called Java as functional language since it supports anonymous object. I thought what a silly statement it was..

Also functional approach has also very good fit with asynchronous programming.
Since we need to generate a function which will be called later time. So this requires to generate a  functions from combining other functions to be executed in later time. (many Stream program depend on then method, which is essentially Future to Future function.)

Asynchronous approach and  Compilation can be also combined further to have a distributed compiler at fine grained level. This will be discussed in another post.

No comments:

Post a Comment