Sponsored Link •
I have just finished a prototype interpreter for Unimperative, a functional programming language which happens to be also valid C++.
Unimperative is my latest creation, a Lisp dialect which is entirely functional but also compiles, without changes but with the appropriate library of course, as C++. I will be posting the source code on my web site in about a week, but here is a taste of what is coming up:
The canonical way to demonstrate a functional language is probably to show the factorial function, so without further ado:
Def Factorial = (If, (Eq, _1, 0), 1, (Mult, _1, (Eval, self, (Dec, _1)) ) );
Def declares the following token is the name of a function. In Unimperative a list, i.e. anything between two paranthesis, is interpreted as a function to be evaluated followed by arguments to that function. Functions in Unimperative are first class and are not evaluated, unless they are the first member of a list, or they are the first argument following the
There are no variables in Unimperative, apart from function variables. The _1, _2, etc., symbols refer to the arguments to the current function. The self is a special symbol which refers to the current function.
Compiling Unimperative in a C++ operator is made possible by using a library of dynamically typed objects, and by sneakily overloading the comma operator.
What makes Unimperative interesting, at least for me, is that it is one of the most portable languages around. It will compile in most any C++ compiler, or can be interpreted wherever an interpreter can be found. This dual nature also makes it very interesting for Agile development, in that testing, refactoring and prototyping can be done in C++ without recompiling, and when the version is stable, the code can be committed to the executable.
For those like me who just can't get enough of sample code, here is my current test suite for both the interepreter and as embedded C++ code:
Def Cadr = (Car, (Cdr, _1)); Def Second = (Cadr, _1); Def Proc = (Noop, nil); Def End = (Noop, nil); Def Head = (Car, _1); Def Tail = (Cdr, _1); Def Sub = (Add, _1, (Neg, _2)); Def IfZero = (If, (Eq, _1, 0), _2, _3); Def NEq = (Not, (Eq, _1, _2)); Def Inc = (Add, _1, 1); Def Dec = (Add, _1, -1); Def IsEmpty = (IsNil, (Head, _1)); Def NotIsEmpty = (Not, (IsEmpty, _1)); Def MapCar = (Cons, (Eval, _1, (Head, _2)), (Eval, self, (Tail, _2))); Def EqZ = (Eq, 0, _1); Def NEqZ = (NEq, 0, _1); Def OutList = (If, (IsEmpty, _1), nil, (Proc, (Out, (Head, _1)), (Eval, self, (Tail, _1)), End) ); Def NthItem = (If, (Or, (EqZ, _1), (IsEmpty, _2) ), (Head, _2), (Eval, self, (Dec, _1), (Tail, _2)) ); Def Accumulate = (If, (IsEmpty, (Tail, _2)), (Head, _2), (Eval, _1, (Head, _2), (Eval, self, _1, (Tail, _2) ) ) ); Def Sum = (Accumulate, Add, _1); Def Factorial = (If, (Eq, _1, 0), 1, (Mult, _1, (Eval, self, (Dec, _1)) ) ); //=========== // Test cases Def TestCompare = (Out, "Expected :", _1, ", Actual :", (Eval, _2, _3)); Def FactorialTests = (Proc, (TestCompare, 1, Factorial, 1), (TestCompare, 120, Factorial, 5), (TestCompare, 3628800, Factorial, 10), End); Def TestListVar = (Cons, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); Def TestNthItem = (NthItem, _1, (Eval, TestListVar)); Def ListsTest = (Proc, (Out, "Expecting 1 to 10"), (OutList, (Eval, TestListVar)), (TestCompare, 0, TestNthItem, 0), (TestCompare, 1, TestNthItem, 1), (TestCompare, 5, TestNthItem, 5), (TestCompare, 9, TestNthItem, 9), (TestCompare, 1, Sum, (Cons, 1)), (TestCompare, 10, Sum, (Cons, 1, 2, 3, 4)), (TestCompare, 15, Sum, (Cons, 1, 2, 3, 4, 5)), End); Def AllTests = (Proc, (FactorialTests, nil), (ListsTest, nil), End);
|Christopher Diggins is a software developer and freelance writer. Christopher loves programming, but is eternally frustrated by the shortcomings of modern programming languages. As would any reasonable person in his shoes, he decided to quit his day job to write his own ( www.heron-language.com ). Christopher is the co-author of the C++ Cookbook from O'Reilly. Christopher can be reached through his home page at www.cdiggins.com.|