views:

4594

answers:

10

Lua's most direct competitor in the scripting arena is Python. So it commonly gets compared with Python, however I've heard many times that Lua is very much like Lisp(Scheme) in terms of expressive power and flexibility.

Now I'm a Lua power-user, and know its intricacies in and out, but I've only tried Lisp once or twice, so obviously I'm by no means an expert, so I was wondering what kind of features does Lisp have that Lua is missing, if any?

Edit: Some findings:

Reading Greg Hewgill's suggested article and the Wikipedia article I've found the following points:

Some shared points:

-In Lisp Code you have Lambda, same with Lua

-In Lisp Code and Data are the same, same with Lua (See code example below).

-In Lisp functions are not special, same with Lua.

-In Lisp Everything is stored in a tree fashion, same with Lua (not as obvious but its the case)

-In Lisp you have S-expressions, in Lua the entire enviroment is a table, and tables have the power of S-expressions, so it's probably the same, not sure.

-Both Languages have true tail-calling semantics

-Lisp has only Atoms and Lists, Lua has only Variables and Tables, the end result, and power is the same (I think)

Lisp can do, but require advanced techniques, or can't be done in Lua

-In Lisp you can make operators be anything, this is somewhat possible with Lua, however it requires metatables, and so the operators can be anything for certain closures and objects, but not globally.

-In Lisp you have Macros, In Lua you don't, but you have metatables. I can't think of a trick you could do with Macros that can't be done with Lua's regular syntax, but its a point. (See MetaLua below for an example of a true Macro extension and how this can actually be done in Lua)

-Lisp has prefix notation (+ 1 2 3 4), Lua doesn't have this

-in Lisp, you can freely mix Function parameters "required, optional, keyword, and rest parameters", in Lua there is no distinction between parameters, so you need to check by hand

Lua can do, and I have no idea if Lisp can do it

-In Lua you can swap closures and enviroments (global included) in and out at runtime, can Lisp do this?

-In Lua you can swap metatables (similar to C++ virtual tables, but more powerful) on objects and modify them at any time, during compilation or runtime, can Lisp do this?

-In Lua you have fully functional closures, does Lisp have this?

-In Lua tables can become functors, can Lisps lists do this? (I think the S-expressions allow for this, but not sure)


Lisp-like Macros also has been implemented in Lua as such with MetaLua library:

----------------------------------------------------
-- Lambda-Calculus evaluator (weak head normal form)
----------------------------------------------------              
-{ extension "match" }

function replace(var, newval, term)
   match term with
   | `Var{ v } if v==var -> return newval
   | `Var{ _ } -> return term
   | `Apply{ f, x } -> 
      return `Apply{ replace(var, newval, f), replace(var, newval, x) }
   | `Lambda{ v, _ } if v==var -> return term
   | `Lambda{ v, b } ->
      return Lambda{ v, replace(var, newval, b) }
   end
end

function reduce_whnf(term)
   match term with
   | `Apply{ `Lambda { param, body }, arg } ->
      local x = replace (param, arg, body)
      return reduce_whnf(x)
   | _ -> return term
   end
 end


There are those skeptical that Lua is in fact code and data, so I'll pull an example and quote from the manual:

This below is Code or Data depending on how you look at it, because entry may be anything, it can easily process the data bellow, but that data bellow could also be something more code-like. Anyways I haven't seen any example of Lisp doing something code-data related that Lua can't do just as easily. If an example of Lisp is available I'll try to match it with Lua, if I'm not totally wrong.

entry{
  title = "Tecgraf",
  org = "Computer Graphics Technology Group, PUC-Rio",
  url = "http://www.tecgraf.puc-rio.br/",
  contact = "Waldemar Celes",
  description = [[
    TeCGraf is the result of a partnership between PUC-Rio,
    the Pontifical Catholic University of Rio de Janeiro,
    and <A HREF="http://www.petrobras.com.br/"&gt;PETROBRAS&lt;/A&gt;,
    the Brazilian Oil Company.
    TeCGraf is Lua's birthplace,
    and the language has been used there since 1993.
    Currently, more than thirty programmers in TeCGraf use
    Lua regularly; they have written more than two hundred
    thousand lines of code, distributed among dozens of
    final products.]]
  }

And quoting the book it says:

The interesting thing about this representation is that a file with a sequence of such entries is a Lua program


Also here is a wikibook in which the author duplicates the code samples (in Lua) featured in Paul Graham's "On Lisp". As proof that Lua can do anything Lisp can in the functional programming area. (Disclaimer, remember I'm not a Lisper so I can't back this statement personally)


Here is an SO link to some other cool things Lua can do, that I don't know if Lisp can

+6  A: 

A really good article on this topic is The Nature of Lisp. The key point about Lisp and its dialects is that code and data have the exact same representation as a data structure. Therefore, you can write code that creates more code (as Lisp macros do). Also, you can write code to read code as a data structure and manipulate it.

I know about as much about Lua as you do about Lisp, but from what I've read about Lua this sort of fully flexible macro capability is not available.

Greg Hewgill
Thanks for the link, Greg. I'm just starting to think about starting to think about poking LISP with a stick to see what the big deal is for myself. "The Nature of Lisp" article was nice and painless. Now what'd I do with that stick?
Dan Malkinski
everyone misunderstand this: the point is not in the "exact same"-ness of code and data in lisp. the point is that lisp provides various interfaces (including macros) to the compiler framework that take their input in a structured data format. (which is obviously easier to manipulate than free text)
Attila Lendvai
+1  A: 

I only know about Lua from skimming the tutorials, and it seems that it has comparable power to Lisp, but I am a bit unconvinced of some syntactic issues:

  • Function parameters: in Lisp, you can freely mix required, optional, keyword, and rest parameters
  • It seems that in Lua, statements end at a newline. Is it possible to break a statement over several lines?
  • I find prefix notation more expressive and flexible than the use of infix operators (this may be a personal preference).

Apart from that, I have not yet found a system comparable to Lisp macros, but Lua advertises as being an "extensible extension language", so there has to be something like that, is there?

edit: Picking on a different question, Common Lisp has seamless integration (with automatic conversion) for fixnums, bignums, ratios, floats, and complex numbers. Mostly, it will do exactly the right thing.

Svante
Lua can auto-compile its self, so its full circle, even more so than Macros because you can have Lua, parse Lua that parses Lua and so forth recrusively, also you can statically re arrange function calls in runtime, with simple assignemnt operations, but it doesn't have a distinct Macro extension.
Robert Gould
In Lua statements can also end with semi-colon , but you can also write everything on a single line if your careful, just like with C.Lua function parameters aren't as free form, you don't have required parameters for example, so it requires assertion
Robert Gould
In Lua, you can, without problem, split a long statement over several lines, newline is a white space like others between tokens. It is even the source of some syntactic limitations, since semi-colon is optional.
PhiLho
Common Lisp's auto-conversion of numeric types is pretty good, but it falls down in the way it turns exact numeric types (rationals, fixnums and bignums) to floating point types. The exact number is converted to the least precise type (usually a single-float) instead of the most precise type (usually a double-float).
Pillsy
Pillsy: How do you convert? If you use both single-floats and double-floats in a computation, then the result can only be single-float---if it were double-float, it would lie about its precision.
Svante
Svante: A number of functions (like `LOG`) will by necessity return inexact results for exact arguments. However, they'll return single-float answers.
Pillsy
Pillsy: Yes, but you can coerce LOG's argument to double-float first, and it will return a double-float then.
Svante
Lua has the advantage of not having to deal with that number-type silliness. :)
RCIX
RCIX, not using any integers is a convenient generalization for a script language, but for a general purpose language, you shouldn't need to recompile your interpreter/compiler in order to get to work with the, for your computation, most efficient number type on the underlying hardware.
Svante
In general, you don't explicitly deal with number types in Lisp, either. Only when you have specific requirements, you add type declarations/annotations. In Lua, when you have specific requirements, you need to switch the entire compiler, and, as far as I understood, you can't even have different number types in the same running program.
Svante
+4  A: 

I don't know anything about Lua's metaprogramming facilities, but comparing raw capability isn't of much use when comparing programming languages. What makes Lisp macros special isn't the fact that they exist. That's more of a compiler feature than a language feature, anyway. In principle, you can add a macro system to most languages. The important thing about Lisp macros is that (1) they're incredibly simple and (2) they integrate well with the rest of the system. If you want (1), there's practically no way around a syntax as simple as Lisp's.

Matthias Benkard
Found MetaLua http://metalua.luaforge.net/quicktour.html it provides the same level of macro functionality as Lisp (or so they claim)
Robert Gould
As Matthias said it's not a question of whether Lua _has_ macros, but how natural they are. I can write a macro-package for C that does C macros with lisp semantics, but that doesn't mean that they are a naturall extension of the language.
JBF
+19  A: 

Scheme (a LISP dialect) has first class continuations, even if Lua has continuations I don't think they are first class. Whether you want first class continuations or not that's another question.

Also the statement that environments as tables is as powerful as s-expressions is quite pointless. A lot of things are equally powerful, that doesn't make them equally usable. The fact is that the S-expressions and the lisp version of 'code as data' makes writing programs that write programs (macros in this case) very easy. You can do that in other languages (the equally powerful ones) but it isn't as natural, easy or elegant.

As far as I have seen no other language has an equally usable 'code as data' feature that s-expressions give lisp. What you want is not the fact that code could be stored as data, it's the fact that you operate on code with the same ease an on data, and S-expressions is the key to that. If you have infix notation you have to parse and operate on the AST which isn't that natural.

I think your own question highlights one of the important differences: "-In Lua tables can become functors, can Lisps lists do this? (I think the S-expressions allow for this, but not sure)". In lisp there isn't really a become (well you can compile, but that's another matter). S-expressions are, and you evaluate them.

Also lisp is traditionally a compiled language, and compilation (often) means faster.

BUT none of this really matters that much. While lisp is (as of yet) my ideal language, from what I have seen of lua, which one you choose for a particular project is not dependent on language power, but other circumstances.

JBF
Thanks for the S-expression part. My main concern isn't pure power, but understanding how they differ, since I've heard people compare the two. Anyways thanks to everyone here the differences are becoming clearer
Robert Gould
"Also lisp is traditionally a compiled language, and compilation (often) means faster." --I've benchmarked LuaJit against some Scheme implementations, and none of the Schemes were faster. I prefer Scheme, not Lua, but I have to say that Lua is a *great* achievement!
Jay
FWIW Scheme is often interpreted. I should probably have said "the dialects of lisp that evolved to common lisp are traditionally compiled".For a compiled scheme, have a look at Gambit Scheme.More interesting is perhaps which schemes you benchmarked?That said, I would guess that Lua+jit have the potential to be very fast.
JBF
+2  A: 

just wanted to point out that this is a typical starting question of a turing complete discussion leading to an endless debate where parties try to articulate objective differences where there's none...

obviously there are a lot of subjective answers, but they are all worth as much as they do.

that's why i give my meta answer instead... :)

Attila Lendvai
+4  A: 

The key difference between Lua and Lisp dialects is that Lisp macros let you do stuff at compile-time, i.e. without run-time penalties (if you do it correctly). Thus, many things which would bear an impractical run-time cost in other languages make sense in Lisp. Moreover, they give you arbitrary control on your code's syntax, thus letting you keep things readable (again, if you do it correctly).

For examples, look at Common Lisp's CLOS object system, or the LOOP macro: may Lispers consider those overkills, but they nicely show what macros bring you.

Now the key difference between Metalua and Lisp dialects is the "now it's worth it" threshold for macros: they're a bit more complex to write in Metalua, largely because macros have to adapt to the language's syntax rather than the other way around. It's OK, within reasonable limits: what really matters is ease of use of already-written macros. And anyway, people who can't cope with the parser combinator which handles Metalua's syntax probably can't write a semantically sound macro either :)

+3  A: 

A couple of secondary points:

  • it's extremely misleading to talk about "Lisp" as a generic language: there's probably more difference between Scheme, Common Lisp and Clojure than between Lua, Python and Ruby.

  • Python and Lua are almost diametrically opposed in their canonical usages. Python's main asset is its "batteries included" standard library: most of the time, 80% of the program you're about to write already exists as Python mature libraries, and that's why you should use Python most of the time. Lua is intended for when you have the core features (a game engine, an image manipulation lib...), and you "just" need glue to make it easy to exploit: you already have the batteries, and you need something to make them easy to handle.

In all fairness there is a primitive set of batteries for Lua...http://www.lua.org/manual/5.1/manual.html#5
Nick
+5  A: 

I have done a fair amount of programming in Lua and have tried to play around with scheme occasionally. At the moment I can't see how you can treat code as data in Lua while it is quite obvious to me that you can do this in scheme.

I don't think your

  entry{
   title = "Tecgraf",
   org = "Computer Graphics Technology Group, PUC-Rio",
   url = "http://www.tecgraf.puc-rio.br/"
  }

example really shows data lua can treat code as data unless I miss something.

In lua this is a bunch of code called in sequence:

a()
b()
c()

How do I manipulate this list of code? In scheme this sequence of code would be

((a) (b) (c))

Which is a regular scheme list. And Scheme list can be manipulated. I can take this list of code as an argument to a function and shuffle around the code. How can you do the same in Lua? You can't take a chunk of Lua code and rearrange the statements.

Lua code is not expressed as hashtable entries so I don't see that lua hash table as as flexible as the Scheme ones.

The problem with Lua and any other language that tries to mimic the power of LISP is essentially that they try to come up with a nice and more human readable syntax. But the power of LISP comes from its horrible syntax. You can't recreate that power without having and equally horrible syntax to LISP. By horrible I don't mean in the perl kind of way. In that it is all a mess. LISP syntax is extremely regular and simple. That is what makes it both powerful and hard to read for humans.

On the positive side, this horrible syntax makes it possible to add macros to the language without adding almost any complexity. Which makes the syntax for macros in LISP easier than anywhere else. Language with more readable syntax like C++. which have added macros have ended up with an extremely complicated macro syntax.

Adam Smith
function a () print "a" end function b () print "b" end function c () print "c" end fs = { a, b, c } for _,f in ipairs (fs) do f () end
Samuel Danielson
Not the same. You can't shuffle around: a(1, 2) b(3, 4) in Lua, while ((a 1 3) (b 3 4)) can be shuffled around. And a could be e.g. an if statement in Scheme, because if, while etc are just function call. You can't move a if statement around in a lua chunk.
Adam Smith
+1  A: 

I'm only vaguely familiar with Lua, but there are a few couple of aspects Lisp that I think are worth highlighting.

  1. Lisp is a family of languages, not a single language, and within that family of languages, there are often multiple different implementations of the same language. The three most commonly used Lisp dialects are probably Scheme, Common Lisp and Emacs Lisp, and they all have very different goals.

  2. You suggest that in Lisp "everything is an atom or a list", but the Lisp dialects people actually use today are never limited to just lists as data types. Common Lisp, which I use most frequently, offers vectors, multidimensional arrays, strings and hash tables, as well as user-defined classes. The situation is not so different in Scheme and Emacs Lisp.

Pillsy
+1  A: 

The key to Lisp macros is that, if they did not exist, the could be written using nothing but the existing Lisp. This is quite possible in Lua.

In Lisp, source (after reading it) is S-expressions, and Lisp works on S-expressions.

In Lua, source is text, and Lua works on text.

I rather dislike Lua Macros, because they require a hacked Lua. I rather dislike MetaLua, because it isn't very Lua-like.

I prefer my system, where a chunk can be called out at compile-time, itself compiled and executed, and the result spliced back into the source code. It's rather simple string substitution, really.

raito