The Artima Developer Community
Sponsored Link

Weblogs Forum
Unimperative: A Lisp Dialect and a C++ Subset

3 replies on 1 page. Most recent reply: Feb 7, 2005 8:59 PM by Christopher Diggins

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 3 replies on 1 page
Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Unimperative: A Lisp Dialect and a C++ Subset (View in Weblogs)
Posted: Feb 7, 2005 8:59 PM
Reply to this message Reply
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);


Alastair Patrick

Posts: 3
Nickname: alpatrick
Registered: Dec, 2004

Re: Unimperative: A Lisp Dialect and a C++ Subset Posted: Feb 7, 2005 10:03 PM
Reply to this message Reply
That's awesome! I would love to see the source code behind that. I'm going to guess that it is dynamically typed? If so, would it be possible to make it statically typed and what impact would that have on the clean syntax? I only ask because, if one wants to be able to compile it with a C++ compiler, that might mean there is a performance concern. Of course, perhaps the biggest advantage is the portability of C++.

I am actually working on a similar project right now. But rather than a functional sub-language, I am aiming at a Java-like C++ sub-language supporting reflection and automatic memory management. The idea is to get some of the advantages of Java on a platform (video games console) without a JVM. See the link in my profile if you're interested.

Al

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Unimperative: A Lisp Dialect and a C++ Subset Posted: Feb 8, 2005 12:07 AM
Reply to this message Reply
> That's awesome!

Thanks.

>I would love to see the source code behind
> that.

In a week or two (possibly more) it should be posted all at http://www.ootl.org .

> I'm going to guess that it is dynamically typed?

Yes, I currently use boost::any but I will soon be switching to an updated version of the ootl::object class.

> If
> so, would it be possible to make it statically typed and
> what impact would that have on the clean syntax?

Yes. A typed version could be trivially implemented as:

Def<int, int> IntAdd = (Add, x, y);

> I only
> ask because, if one wants to be able to compile it with a
> C++ compiler, that might mean there is a performance
> concern.

It is very slow for the time being. Only about 40% faster compiled than interpreted. It is very immature however.

> Of course, perhaps the biggest advantage is the
> portability of C++.

That's what I was striving for.

> I am actually working on a similar project right now. But
> rather than a functional sub-language, I am aiming at a
> Java-like C++ sub-language supporting reflection and
> automatic memory management. The idea is to get some of
> the advantages of Java on a platform (video games console)
> without a JVM. See the link in my profile if you're
> interested.

Good luck with that!

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Unimperative: A Lisp Dialect and a C++ Subset Posted: Feb 14, 2006 9:01 AM
Reply to this message Reply
> That's awesome! I would love to see the source code behind
> that. I'm going to guess that it is dynamically typed? If
> so, would it be possible to make it statically typed and
> what impact would that have on the clean syntax?

I thought you might be interested to know that Unimperative has been rejuvenated at http://www.unimperative.com as a typed concatenative language.

Flat View: This topic has 3 replies on 1 page
Topic: Can You Write Quality Software Quickly? Previous Topic   Next Topic Topic: The Joy of Joy


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us