Difference between revisions of "HsLua"

From HaskellWiki
Jump to navigation Jump to search
 
 
(9 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
What is Lua? It's a scripting language (like Perl) targeted to be
(this page isn't yet finished)
 
 
easily integrated into any host application. You can do it in
 
what is Lua? it's the scripting language (like Perl) targeted to be
 
easily integrated into any host application. you can do it in
 
 
literally 5 minutes. let's try:
 
literally 5 minutes. let's try:
   
 
== Example 1: running Lua scripts ==
 
== Example 1: running Lua scripts ==
   
First, you need to download and unpack brilliant HsLua package [1]
+
First, you need to download and unpack the HsLua package:
 
http://hackage.haskell.org/package/hslua
written by Gracjan Polak:
 
http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hslua-0.2
 
   
as usual, in order to build and install Cabalized package, run commands:
+
As usual, in order to build and install the package, run the usual commands:
 
<haskell>
 
<haskell>
runhaskell Setup.hs configure
+
cabal configure
  +
cabal install
runhaskell Setup.hs build
 
runhaskell Setup.hs install
 
 
</haskell>
 
</haskell>
  +
Note that the lua version that is linked to can be changed via cabal flags: consult the package docs for details.
(assuming that you have ghc 6.6 or 6.8 installed)
 
   
   
The simplest work where Lua may be handy is replacing application
+
The simplest work where Lua may be handy is in replacing application
config files with scripts. This allows to define complex data
+
config files with scripts. This allows one to define complex data
structures and utilize power of full-fledged programing language. for
+
structures and utilize the power of a full-fledged programming language. For
 
example, the following "config" file, written in Lua:
 
example, the following "config" file, written in Lua:
   
Line 33: Line 29:
 
environment vars USER/PWD, but substitutes default values if they are
 
environment vars USER/PWD, but substitutes default values if they are
 
not defined. The following Haskell program demonstrates how to get
 
not defined. The following Haskell program demonstrates how to get
into your hands values defined in such unusual way:
+
your hands on values defined in such an unusual way:
   
 
<haskell>
 
<haskell>
import qualified Scripting.Lua as Lua
+
import Foreign.Lua
main = do
 
l <- Lua.newstate
 
Lua.openlibs l
 
   
 
main = runLua $ do
Lua.dofile l "configfile.lua"
 
 
openlibs
Right name <- Lua.dostring l "return username"
 
Right pwd <- Lua.dostring l "return password"
 
   
 
dofile "configfile.lua"
print (name::String, pwd::String)
 
  +
name <- getglobal "username" *> peek (-1)
Lua.close l
 
  +
pwd <- getglobal "password" *> peek (-1)
  +
 
liftIO $ print (name::String, pwd::String)
 
</haskell>
 
</haskell>
   
voila! are you finished in 5 minutes? :)
+
Voila! Are you finished in 5 minutes? :)
   
   
What we are doing here? First, we create new instance of Lua
+
What we are doing here? The command "openlibs" imports built-in Lua functions into this lua instance.
 
Note that fresh Lua instances only have access to a dozen standard
interpreter using "newstate". Lua implementation doesn't use global
 
vars that means that you can create as much Lua instances as you need
 
and run them all simultaneously
 
 
Then, "openlibs" imports builtin Lua functions into this instance.
 
Note that fresh Lua instance have access only to a dozen of standard
 
 
(arithmetic) operations. By careful selection of functions provided
 
(arithmetic) operations. By careful selection of functions provided
to Lua instance, you can turn it into sandbox - i.e. disallow access
+
to the Lua instance, you can turn it into sandbox - e.g. disallow access
 
to file system, network connections and so on, or provide special
 
to file system, network connections and so on, or provide special
functions which can access only specific directory/host/whatever
+
functions which can access only specific directory/host/whatever.
 
Next operation, "dofile", runs script from file specified. This script
 
defines variables "username" and "password" that we then read by
 
"eval". Finally, "close" destructs Lua instance, freeing memory it has
 
grabbed
 
   
 
The next operation, "dofile", runs script from file specified. This script
  +
defines the global variables "username" and "password". The function "getglobal" pushes the respective variable to the top of Lua's stack, which is used by Lua to communicate with external programs. We then turn the value at the top of the stack (i.e., at stack index <code>(-1)</code>) into a haskell value by using "peek".
   
 
== Example 2: calling from Haskell to Lua ==
 
== Example 2: calling from Haskell to Lua ==
   
Now imagine that we need more complex config capable to provide for
+
Now imagine that we need more complex config capable of providing for
each site we are log in its own user/pwd pair. we can write it either
+
each site we have an account in its own user/pwd pair. We can write it either
as associative table or as a function mapping site name to user/pwd.
+
as an associative table, or as a function mapping site name to user/pwd.
let's combine both approaches:
+
Let's combine both approaches:
   
 
<haskell>
 
<haskell>
Line 93: Line 80:
 
</haskell>
 
</haskell>
   
and replace in Haskell program reading of variables with call to function:
+
and replace in the first Haskell program, the reading of variables with a call to the new function 'getuserpwd':
   
 
<haskell>
 
<haskell>
[name,pwd] <- Lua.callfunc l "getuserpwd" "mail.google.com"
+
(name,pwd) <- callFunc "getuserpwd" "mail.google.com"
 
</haskell>
 
</haskell>
 
   
 
== Example 3: calling from Lua to Haskell ==
 
== Example 3: calling from Lua to Haskell ==
   
But that's not the whole story. When Lua used as scripting language
+
But that's not the whole story. When Lua is used as a scripting language
 
inside your application, the communication should be two-forked.
 
inside your application, the communication should be two-forked.
imagine for example that you develop a game and Lua scripts are used
+
Imagine, for example, that you develop a game and Lua scripts are used
to control game characters. while Lua script fully defines their
+
to control game characters. While the Lua script fully defines their
behavior logic, it should command something that will render this
+
behavioural logic, it should command something that will render this
behavior to the player. just for example:
+
behaviour to the player. Just for example:
   
 
<haskell>
 
<haskell>
Line 116: Line 102:
 
</haskell>
 
</haskell>
   
this script commands our character to go 1 step forward, 2 steps backward
+
This script commands our character to go 1 step forward, 2 steps backward
repeating this 3 times. the "move" procedure here should be defined
+
repeating this 3 times. The "move" procedure here should be defined
on Haskell side to show his behavior. let's go:
+
on Haskell side to show his behaviour. Let's go:
   
 
<haskell>
 
<haskell>
import qualified Scripting.Lua as Lua
+
import qualified Foreign.Lua as Lua
   
hsMove :: Int -> String -> IO ()
+
hsMove :: LuaInteger -> String -> Lua ()
hsMove n direction = do
+
hsMove (LuaInteger n) direction = do
putStrLn$ "going "++show n++" step(s) "++direction
+
putStrLn $ "going " ++ show n ++ " step(s) " ++ direction
   
main = do
+
main = runLua $ do
 
Lua.registerHaskellFunction "move" hsMove
l <- Lua.newstate
 
 
Lua.dofile "game.lua"
 
Lua.register l "move" hsMove
 
Lua.dofile l "game.lua"
 
 
Lua.close l
 
 
</haskell>
 
</haskell>
   
The only new call here is "register" which registers Haskell function
+
The only new call here is "registerHaskellFunction" which registers a Haskell function
in Lua instance. Please note that we may call any Lua
+
in with Lua instance. Please note that we may call any Lua
 
function/procedure from Haskell (as we've done in previous example)
 
function/procedure from Haskell (as we've done in previous example)
 
and register any Haskell procedure in Lua as far as their arguments
 
and register any Haskell procedure in Lua as far as their arguments
and results has simple enough types (numbers, strings, booleans, lists
+
and results has simple enough types (lua numbers, strings, booleans, lists
and maps). In such simple cases HsLua takes in its hands all the
+
and maps; anything that can be pushed to and received from the Lua stack). In such simple cases HsLua takes in its hands all the
conversions of data between Haskell and Lua worlds
+
conversions of data between Haskell and Lua worlds.
   
Also note that we omitted here call to "openlibs", making Lua instance
+
Also note that we omitted here a call to "openlibs", making Lua instance
 
a real sandbox - all the communication with external world that script
 
a real sandbox - all the communication with external world that script
 
can do is to move it, move it :)
 
can do is to move it, move it :)
 
   
 
== Exchanging data between Haskell and Lua worlds ==
 
== Exchanging data between Haskell and Lua worlds ==
   
Lua variables have dynamic values. When we cast these values from/to
+
Lua variables have dynamic types. When we cast these values from/to
Haskell world, they are mapped to the appropriate Haskell types. Type
+
Haskell world, they are mapped to the appropriate Haskell types. The type
class StackValue covers Haskell types that can be casted from/to Lua
+
classes ''FromLuaStack'' and ''ToLuaStack'' cover Haskell types that can be casted from/to Lua
 
values and defines the casting rules. Predefined class instances
 
values and defines the casting rules. Predefined class instances
include Int, Double, String, Bool, [a] for lists and [(a,b)] for maps
+
include LuaInteger, String, Bool, Text, [a], and Data.Map.Map a b for maps
where a and b may be any StackValue types again. There is also
+
where a and b may be any type that's an instance of the respective type class again. Heterogenous data can be passed via hslua-aeson, treating Lua values as JSON-like data.
existential class wrapper XXX that allows to pass heterogeneous
 
collections (lists/maps) from Haskell to Lua:
 
 
<haskell>
 
Lua.callproc "foo" [XXX True, XXX "str", XXX [1,2,3]]
 
Lua.callproc "bar" [(XXX 1, XXX True), (XXX 2, XXX "str"), (XXX "tag", XXX 3.14])]
 
</haskell>
 
   
 
HsLua includes two operations which just execute operators in context
 
HsLua includes two operations which just execute operators in context
of given Lua instance: "dofile" and "dostring" (executing contents of
+
of a given Lua instance: ''dofile'' and ''dostring'' (executing contents of file and string, respectively). They return ''OK'' on success and an error code
file and string, respectively). They return 0 on success and errcode
 
 
otherwise:
 
otherwise:
   
 
<haskell>
 
<haskell>
dofile :: LuaState -> String -> IO Int
+
dofile :: String -> Lua Status
dostring :: LuaState -> String -> IO Int
+
dostring :: String -> Lua Status
 
</haskell>
 
</haskell>
   
Two other operations return result of executing string/file: "eval"
 
and "evalfile", respectively. "eval" may also be used to evaluate
 
expressions, as it was done in our first script. These operations
 
return (Right a) on success, where "a" may be any type belonging to
 
StackValue class. On error they return (Left Int) where Int will be
 
either errcode or 0 if casting was unsuccessful:
 
   
  +
The next important operation is ''callFunc''. It calls a
<haskell>
 
 
Lua function passing to it arbitrary number of arguments.
eval :: (StackValue a) => LuaState -> String -> Either Int a
 
evalfile :: (StackValue a) => LuaState -> String -> Either Int a
 
</haskell>
 
 
The next operations pair is "callfunc" and "callproc". They both call
 
Lua function passing to it arbitrary number of arguments. The only
 
difference is that "callfunc" returns and "callproc" omits return
 
value of Lua function called:
 
   
 
<haskell>
 
<haskell>
  +
-- the actual type is slightly different to simulate a variadic function.
callfunc :: (StackValue x1, x2 ... xn, a) =>
 
LuaState -> String -> x1 -> x2 ... xn -> Either Int a
+
callfunc :: (ToLuaStack x1, x2 ... xn, FromLuaStack a)
callproc :: (StackValue x1, x2 ... xn) =>
+
=> String -> x1 -> x2 ... xn -> Lua a
LuaState -> String -> x1 -> x2 ... xn -> IO Int
 
 
</haskell>
 
</haskell>
   
Finally, "register" operation registers in Lua world any Haskell
+
Finally, ''registerHaskellFunction'' operation registers in the Lua world any Haskell
 
function/procedure that receives and returns values of StackValue types:
 
function/procedure that receives and returns values of StackValue types:
   
 
<haskell>
 
<haskell>
register :: (StackValue x1, x2 ... xn, a) =>
+
registerHaskellFunction :: (FromLuaStack x1, x2 ... xn, ToLuaStack a)
LuaState -> String -> (x1 -> x2 ... xn -> {IO} a) -> IO Int
+
=> String -> (x1 -> x2 ... xn -> Lua a) -> Lua ()
 
</haskell>
 
</haskell>
   
  +
n &ge; 0, i.e.
where {IO} means that IO specifier is optional here. n>=0, i.e.
 
 
register/callfunc/callproc may also register/call functions having
 
register/callfunc/callproc may also register/call functions having
no arguments
+
no arguments.
 
   
 
== About Lua ==
 
== About Lua ==
Line 229: Line 187:
 
concurrency/coroutines/iterators. But special syntax for advanced
 
concurrency/coroutines/iterators. But special syntax for advanced
 
features is almost non-existent and in many cases Lua gives you only
 
features is almost non-existent and in many cases Lua gives you only
base on which you should build yourself. For example, OOP inheritance
+
a base on which you have to build yourself. For example, OOP inheritance
 
isn't implemented but there are libraries implementing single and
 
isn't implemented but there are libraries implementing single and
 
multiple inheritance just by manipulating metatables. So while you can
 
multiple inheritance just by manipulating metatables. So while you can
learn Lua basics in a few minutes, i recommend you to spend a few days
+
learn Lua basics in a few minutes, I recommend you to spend a few days
before making a final decision
+
before making a final decision.
   
   
 
== More about Lua ==
 
== More about Lua ==
   
If you want to know more about Lua, you can jump to online book
+
If you want to know more about Lua, you can jump to the online book
 
written by main developer of Lua and describing Lua 5.0 at
 
written by main developer of Lua and describing Lua 5.0 at
 
http://www.lua.org/pil/ or buy new version of this book describing Lua
 
http://www.lua.org/pil/ or buy new version of this book describing Lua
 
5.1 (current version) from Amazon [2]
 
5.1 (current version) from Amazon [2]
   
Official Lua 5.1 manual is at http://www.lua.org/manual/5.1/ - it's
+
The official Lua 5.1 manual is at http://www.lua.org/manual/5.1/ - it's
 
clearly written but definitely not the best place to start
 
clearly written but definitely not the best place to start
   
 
If you need to perform more complex tasks using HsLua library, you
 
If you need to perform more complex tasks using HsLua library, you
 
should study C API for Lua at http://www.lua.org/pil/index.html#24 -
 
should study C API for Lua at http://www.lua.org/pil/index.html#24 -
low-level part of HsLua mainly duplicates this API
+
the low-level part of HsLua mainly duplicates this API
   
 
For me the most interesting part of Lua site is the list of Lua
 
For me the most interesting part of Lua site is the list of Lua
Line 262: Line 220:
 
=== [[http://lua-users.org/wiki/LuaBinaryModules LuaBinaryModules]] ===
 
=== [[http://lua-users.org/wiki/LuaBinaryModules LuaBinaryModules]] ===
   
If user of your application wants to use some Lua library written in
+
If a user of your application wants to use some Lua library written in
 
Lua itself, that's easy - just put the source file into program
 
Lua itself, that's easy - just put the source file into program
 
directory. But what about libraries containing C parts?
 
directory. But what about libraries containing C parts?
Line 271: Line 229:
 
this function is called automatically by LuaBinaryModules loader
 
this function is called automatically by LuaBinaryModules loader
   
as result, LuaBinaryModules allows users of your application to
+
As a result, LuaBinaryModules allows users of your application to
 
install any libraries they need just by copying their dll/so files
 
install any libraries they need just by copying their dll/so files
into application directory
+
into application directory.
   
 
=== LuaJIT ===
 
=== LuaJIT ===
Line 290: Line 248:
 
=== wxLua ===
 
=== wxLua ===
   
wxLua is cross-platform (Windows, Linux, OSX) binding to wxWindows
+
wxLua is a cross-platform (Windows, Linux, OSX) binding to wxWindows
 
library, plus IDE written using this binding that supports debugging
 
library, plus IDE written using this binding that supports debugging
of Lua code and generation of Lua bindings to C libraries. so, you get
+
of Lua code and generation of Lua bindings to C libraries. So, you get
full-featured Lua IDE extensible in Lua itself
+
a full-featured Lua IDE extensible in Lua itself.
   
it is even more interesting that you can add the wxLua to your
+
It is even more interesting that you can add the wxLua to your
 
Lua-enabled application, providing user-written code means to build
 
Lua-enabled application, providing user-written code means to build
full-fledged GUI. just imagine that now you can split your program
+
full-fledged GUI. Just imagine that now you can split your program
 
into two parts - real work is done in Haskell part which registers its
 
into two parts - real work is done in Haskell part which registers its
 
functions for Lua part and all the funny dialogs and editors are
 
functions for Lua part and all the funny dialogs and editors are
written in Lua using wxWindows widgets. Lua part can be easily
+
written in Lua using wxWindows widgets. The Lua part can be easily
 
created/extended by less experienced users meaning that you may spend
 
created/extended by less experienced users meaning that you may spend
more time on implementing core algorithms. isn't it beautiful?
+
more time on implementing core algorithms. Isn't it beautiful?
   
 
=== MetaLua ===
 
=== MetaLua ===
Line 335: Line 293:
 
directory and supports creation of GUIs - seamlessly integrated with
 
directory and supports creation of GUIs - seamlessly integrated with
 
your Haskell code. I think it will be invaluable tool that supplements
 
your Haskell code. I think it will be invaluable tool that supplements
Haskell's power with easiness and flexibility
+
Haskell's power with easiness and flexibility.
   
   

Latest revision as of 18:34, 20 August 2017

What is Lua? It's a scripting language (like Perl) targeted to be easily integrated into any host application. You can do it in literally 5 minutes. let's try:

Example 1: running Lua scripts

First, you need to download and unpack the HsLua package: http://hackage.haskell.org/package/hslua

As usual, in order to build and install the package, run the usual commands:

cabal configure
cabal install

Note that the lua version that is linked to can be changed via cabal flags: consult the package docs for details.


The simplest work where Lua may be handy is in replacing application config files with scripts. This allows one to define complex data structures and utilize the power of a full-fledged programming language. For example, the following "config" file, written in Lua:

username = os.getenv("USER") or "God"
password = os.getenv("PWD")  or "dontdisturb"

assigns to variables "username" and "password" values read from environment vars USER/PWD, but substitutes default values if they are not defined. The following Haskell program demonstrates how to get your hands on values defined in such an unusual way:

import Foreign.Lua

main = runLua $ do
    openlibs

    dofile "configfile.lua"
    name <- getglobal "username" *> peek (-1)
    pwd <- getglobal "password" *> peek (-1)

    liftIO $ print (name::String, pwd::String)

Voila! Are you finished in 5 minutes? :)


What we are doing here? The command "openlibs" imports built-in Lua functions into this lua instance. Note that fresh Lua instances only have access to a dozen standard (arithmetic) operations. By careful selection of functions provided to the Lua instance, you can turn it into sandbox - e.g. disallow access to file system, network connections and so on, or provide special functions which can access only specific directory/host/whatever.

The next operation, "dofile", runs script from file specified. This script defines the global variables "username" and "password". The function "getglobal" pushes the respective variable to the top of Lua's stack, which is used by Lua to communicate with external programs. We then turn the value at the top of the stack (i.e., at stack index (-1)) into a haskell value by using "peek".

Example 2: calling from Haskell to Lua

Now imagine that we need more complex config capable of providing for each site we have an account in its own user/pwd pair. We can write it either as an associative table, or as a function mapping site name to user/pwd. Let's combine both approaches:

function getuserpwd (site)
  local cookies = { ["www.ibm.com"] = {"joe", "secret"}
                  , ["www.sun.com"] = {"hoe", "another secret"}
                  }
  if cookies[site] then
    return cookies[site]
  elseif site:match("[.]google[.]com$") then
    return {"boss", "boss"}
  else
    return { os.getenv("USER") or "God"
           , os.getenv("PWD")  or "dontdisturb" }
  end
end

and replace in the first Haskell program, the reading of variables with a call to the new function 'getuserpwd':

     (name,pwd) <- callFunc "getuserpwd" "mail.google.com"

Example 3: calling from Lua to Haskell

But that's not the whole story. When Lua is used as a scripting language inside your application, the communication should be two-forked. Imagine, for example, that you develop a game and Lua scripts are used to control game characters. While the Lua script fully defines their behavioural logic, it should command something that will render this behaviour to the player. Just for example:

for i=1,3 do
  move( 1, "forward")
  move( 2, "backward")
end

This script commands our character to go 1 step forward, 2 steps backward repeating this 3 times. The "move" procedure here should be defined on Haskell side to show his behaviour. Let's go:

import qualified Foreign.Lua as Lua

hsMove :: LuaInteger -> String -> Lua ()
hsMove (LuaInteger n) direction = do
    putStrLn $ "going " ++ show n ++ " step(s) " ++ direction

main = runLua $ do
    Lua.registerHaskellFunction "move" hsMove
    Lua.dofile "game.lua"

The only new call here is "registerHaskellFunction" which registers a Haskell function in with Lua instance. Please note that we may call any Lua function/procedure from Haskell (as we've done in previous example) and register any Haskell procedure in Lua as far as their arguments and results has simple enough types (lua numbers, strings, booleans, lists and maps; anything that can be pushed to and received from the Lua stack). In such simple cases HsLua takes in its hands all the conversions of data between Haskell and Lua worlds.

Also note that we omitted here a call to "openlibs", making Lua instance a real sandbox - all the communication with external world that script can do is to move it, move it :)

Exchanging data between Haskell and Lua worlds

Lua variables have dynamic types. When we cast these values from/to Haskell world, they are mapped to the appropriate Haskell types. The type classes FromLuaStack and ToLuaStack cover Haskell types that can be casted from/to Lua values and defines the casting rules. Predefined class instances include LuaInteger, String, Bool, Text, [a], and Data.Map.Map a b for maps where a and b may be any type that's an instance of the respective type class again. Heterogenous data can be passed via hslua-aeson, treating Lua values as JSON-like data.

HsLua includes two operations which just execute operators in context of a given Lua instance: dofile and dostring (executing contents of file and string, respectively). They return OK on success and an error code otherwise:

dofile   :: String -> Lua Status
dostring :: String -> Lua Status


The next important operation is callFunc. It calls a Lua function passing to it arbitrary number of arguments.

-- the actual type is slightly different to simulate a variadic function.
callfunc :: (ToLuaStack x1, x2 ... xn, FromLuaStack a)
         => String -> x1 -> x2 ... xn -> Lua a

Finally, registerHaskellFunction operation registers in the Lua world any Haskell function/procedure that receives and returns values of StackValue types:

registerHaskellFunction :: (FromLuaStack x1, x2 ... xn, ToLuaStack a)
                        => String -> (x1 -> x2 ... xn -> Lua a) -> Lua ()

n ≥ 0, i.e. register/callfunc/callproc may also register/call functions having no arguments.

About Lua

A few words about Lua as a language. It's rather close to Perl/Python/Ruby, the main difference is Lua's compactness. In particular, HsLua will add only about 200kb to your program. The Lua syntax definition is just about 40 lines long and omits many modern features such as exception handling or OOP. It provides simple means for doing simple tasks that made it perfect tool for non-professional programmers

But the first impression fools you. Lua is a wolf in sheep's hide. As its author said, "Lua provides Modula syntax but Scheme semantics". The main distinctive feature of Lua is its extensibility. It provides semantical base for implementation of exceptions, OOP, data hiding, metaprogramming, persistency, functional programming, lazy evaluation, concurrency/coroutines/iterators. But special syntax for advanced features is almost non-existent and in many cases Lua gives you only a base on which you have to build yourself. For example, OOP inheritance isn't implemented but there are libraries implementing single and multiple inheritance just by manipulating metatables. So while you can learn Lua basics in a few minutes, I recommend you to spend a few days before making a final decision.


More about Lua

If you want to know more about Lua, you can jump to the online book written by main developer of Lua and describing Lua 5.0 at http://www.lua.org/pil/ or buy new version of this book describing Lua 5.1 (current version) from Amazon [2]

The official Lua 5.1 manual is at http://www.lua.org/manual/5.1/ - it's clearly written but definitely not the best place to start

If you need to perform more complex tasks using HsLua library, you should study C API for Lua at http://www.lua.org/pil/index.html#24 - the low-level part of HsLua mainly duplicates this API

For me the most interesting part of Lua site is the list of Lua libraries, IDEs and other tools at http://lua-users.org/wiki/LuaAddons

I want to shortly introduce things there that were most exciting for me:

  • LuaBinaryModules - compiling C library for Lua into self-described dll/so
  • LuaJIT - increase execution speed up to 7 times
  • wxLua - binding to wxWidgets and IDE with debugger and C bindings generator
  • MetaLua - alternative Lua frontend with FP features and extensible syntax


[LuaBinaryModules]

If a user of your application wants to use some Lua library written in Lua itself, that's easy - just put the source file into program directory. But what about libraries containing C parts? LuaBinaryModules solves this problem - it allows to compile any library for Lua to a dll/so file which may be imported by any Lua instance to get full library functionality. Technically speaking, LBM just adds one more function which registers all library functions and this function is called automatically by LuaBinaryModules loader

As a result, LuaBinaryModules allows users of your application to install any libraries they need just by copying their dll/so files into application directory.

LuaJIT

While Lua bytecode interpreter being register-based VM is fastest among all dynamic languages, sometimes you need even more speed. LuaJIT compiles bytecode instructions into x86 code, improving speed up to 7 times (as tested on Great Language Shootout examples). One of its interesting features is automatic function specialization to the types of actual parameters

I've quickly tested it on simple i=i+1 statements and found that with JIT computer runs at 1/10th of its full speed while without JIT it runs at 1/30th

wxLua

wxLua is a cross-platform (Windows, Linux, OSX) binding to wxWindows library, plus IDE written using this binding that supports debugging of Lua code and generation of Lua bindings to C libraries. So, you get a full-featured Lua IDE extensible in Lua itself.

It is even more interesting that you can add the wxLua to your Lua-enabled application, providing user-written code means to build full-fledged GUI. Just imagine that now you can split your program into two parts - real work is done in Haskell part which registers its functions for Lua part and all the funny dialogs and editors are written in Lua using wxWindows widgets. The Lua part can be easily created/extended by less experienced users meaning that you may spend more time on implementing core algorithms. Isn't it beautiful?

MetaLua

We already mentioned that Lua semantics is rather close, may be a bit better than of other scripting languages, but its syntax is terse. But this simplicity opens up sudden and very exciting possibility - it's easy to reimplement Lua and add any other features we want without losing bytecode compatibility with official implementation

MetaLua does that, reimplementing Lua compiler in Lua itself. But it goes much further: Lua syntax is described in GG, ParseC-like parsing combinators library. Unlike ParseC, it allows to change parsing rules on the fly, making it ideal basis for language with extensible syntax

MetaLua adds to Lua a lot of FP-styled and other features - ADT, pattern matching, terse syntax for anonymous lambdas, list comprehensions, familiar syntax for exception handling, RAII brackets, statements inside expressions, ternary ?: operator, type/domain checking. All these implemented with usual Lua modules and as everything in Lua, they are very terse - the largest module, implementing pattern matching, is just 200 lines long. You can add new syntax just by dropping new modules into MetaLua directory. Extending MetaLua is very like to programming in Template Haskell with all its pitfalls solved and extending-syntax features added. I will be very pleased if GHC provided front-end like the MetaLua


Just imagine all these features combined together: blazing fast dynamic FP language that may be easily extended by means of new libraries and new syntax just by dropping their files into program's directory and supports creation of GUIs - seamlessly integrated with your Haskell code. I think it will be invaluable tool that supplements Haskell's power with easiness and flexibility.


Further reading

[1] http://hackage.haskell.org/packages/archive/hslua/

[2] http://www.inf.puc-rio.br/~roberto/pil2

[3] http://www.lua.org/uses.html

[4] http://lua-users.org/wiki/ThreadsTutorial

[5] http://lua-users.org/wiki/GenericInputAlgorithms