The Artima Developer Community
Sponsored Link

Heron-Centric: Ruminations of a Language Designer
Unimperative: A Lisp Dialect and a C++ Subset
by Christopher Diggins
February 8, 2005
Summary
I have just finished a prototype interpreter for Unimperative, a functional programming language which happens to be also valid C++.

Advertisement

Unimperative is now available at http://www.unimperative.com

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 Eval operator.

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);

Talk Back!

Have an opinion? Readers have already posted 3 comments about this weblog entry. Why not add yours?

RSS Feed

If you'd like to be notified whenever Christopher Diggins adds a new entry to his weblog, subscribe to his RSS feed.

About the Blogger

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.

This weblog entry is Copyright © 2005 Christopher Diggins. All rights reserved.

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use