Personal tools

HsLua

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
(Example 1: running Lua scripts)
(typo)
(One intermediate revision by one user not shown)
Line 1: Line 1:
(this page isn't yet finished)
+
What is Lua? It's a scripting language (like Perl) targeted to be
+
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 brilliant HsLua package [1]
 
written by Gracjan Polak:
 
written by Gracjan Polak:
 
http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hslua
 
http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hslua
   
as usual, in order to build and install Cabalized package, run commands:
+
As usual, in order to build and install Cabalized package, run commands:
 
<haskell>
 
<haskell>
 
runhaskell Setup.hs configure
 
runhaskell Setup.hs configure
Line 15: Line 15:
 
runhaskell Setup.hs install
 
runhaskell Setup.hs install
 
</haskell>
 
</haskell>
(assuming that you have ghc 6.6 or 6.8 installed)
+
(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 47: Line 47:
 
</haskell>
 
</haskell>
   
voila! are you finished in 5 minutes? :)
+
Voila! Are you finished in 5 minutes? :)
   
   
Line 55: Line 55:
 
and run them all simultaneously
 
and run them all simultaneously
   
Then, "openlibs" imports builtin Lua functions into this instance.
+
Then, "openlibs" imports built-in Lua functions into this instance.
Note that fresh Lua instance have access only to a dozen of standard
+
Note that fresh Lua instances have access only to a dozen 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 - i.e. 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
+
The next operation, "dofile", runs script from file specified. This script
defines variables "username" and "password" that we then read by
+
defines variables "username" and "password" that we then read using
"eval". Finally, "close" destructs Lua instance, freeing memory it has
+
"eval". Finally, "close" destructs the Lua instance, freeing memory it has
grabbed
+
grabbed.
   
 
== 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 90: Line 90:
 
</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>
Line 99: Line 99:
 
== 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 113: Line 113:
 
</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>
Line 139: Line 139:
 
and results has simple enough types (numbers, strings, booleans, lists
 
and results has simple enough types (numbers, strings, booleans, lists
 
and maps). In such simple cases HsLua takes in its hands all the
 
and maps). 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. Type
 
class StackValue covers Haskell types that can be casted from/to Lua
 
class StackValue covers 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 Int, Double, String, Bool, [a] for lists and [(a,b)] for maps
where a and b may be any StackValue types again. There is also
+
where a and b may be any StackValue types again. There is also an
 
existential class wrapper XXX that allows to pass heterogeneous
 
existential class wrapper XXX that allows to pass heterogeneous
 
collections (lists/maps) from Haskell to Lua:
 
collections (lists/maps) from Haskell to Lua:
Line 163: Line 162:
   
 
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 0 on success and errcode
 
file and string, respectively). They return 0 on success and errcode
 
otherwise:
 
otherwise:
Line 176: Line 175:
 
expressions, as it was done in our first script. These operations
 
expressions, as it was done in our first script. These operations
 
return (Right a) on success, where "a" may be any type belonging to
 
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
+
StackValue class. On an error they return (Left Int) where Int will be
 
either errcode or 0 if casting was unsuccessful:
 
either errcode or 0 if casting was unsuccessful:
   
Line 184: Line 183:
 
</haskell>
 
</haskell>
   
The next operations pair is "callfunc" and "callproc". They both call
+
The next pair of operations is "callfunc" and "callproc". They both call a
 
Lua function passing to it arbitrary number of arguments. The only
 
Lua function passing to it arbitrary number of arguments. The only
difference is that "callfunc" returns and "callproc" omits return
+
difference is that "callfunc" returns and "callproc" omits the return
 
value of Lua function called:
 
value of Lua function called:
   
Line 196: Line 195:
 
</haskell>
 
</haskell>
   
Finally, "register" operation registers in Lua world any Haskell
+
Finally, "register" 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:
   
Line 204: Line 203:
 
</haskell>
 
</haskell>
   
where {IO} means that IO specifier is optional here. n>=0, i.e.
+
where {IO} means that the 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.
   
   
Line 226: Line 225:
 
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 259: Line 258:
 
=== [[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 268: Line 267:
 
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 287: Line 286:
 
=== 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 332: Line 331:
 
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.
   
   

Revision as of 18:03, 3 October 2010

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:

Contents

1 Example 1: running Lua scripts

First, you need to download and unpack the brilliant HsLua package [1] written by Gracjan Polak: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hslua

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

runhaskell Setup.hs configure
runhaskell Setup.hs build
runhaskell Setup.hs install

(Assuming that you have ghc 6.6 or 6.8 installed)


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 into your hands values defined in such unusual way:

import qualified Scripting.Lua as Lua
main = do
    l <- Lua.newstate
    Lua.openlibs l
 
    Lua.dofile l "configfile.lua"
    Right name <- Lua.dostring l "return username"
    Right pwd  <- Lua.dostring l "return password"
 
    print (name::String, pwd::String)
    Lua.close l

Voila! Are you finished in 5 minutes? :)


What we are doing here? First, we create new instance of Lua 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 built-in Lua functions into this instance. Note that fresh Lua instances have access only to a dozen standard (arithmetic) operations. By careful selection of functions provided to the Lua instance, you can turn it into sandbox - i.e. 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 variables "username" and "password" that we then read using "eval". Finally, "close" destructs the Lua instance, freeing memory it has grabbed.

2 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] <- Lua.callfunc l "getuserpwd" "mail.google.com"


3 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 Scripting.Lua as Lua
 
hsMove :: Int -> String -> IO ()
hsMove n direction = do
    putStrLn$ "going "++show n++" step(s) "++direction
 
main = do
    l <- Lua.newstate
 
    Lua.register l "move" hsMove
    Lua.dofile l "game.lua"
 
    Lua.close l

The only new call here is "register" which registers Haskell function in 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 (numbers, strings, booleans, lists and maps). 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 :)

4 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. Type class StackValue covers Haskell types that can be casted from/to Lua values and defines the casting rules. Predefined class instances include Int, Double, String, Bool, [a] for lists and [(a,b)] for maps where a and b may be any StackValue types again. There is also an existential class wrapper XXX that allows to pass heterogeneous collections (lists/maps) from Haskell to Lua:

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

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 0 on success and errcode otherwise:

dofile   :: LuaState -> String -> IO Int
dostring :: LuaState -> String -> IO Int

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 an error they return (Left Int) where Int will be either errcode or 0 if casting was unsuccessful:

eval     :: (StackValue a) => LuaState -> String -> Either Int a
evalfile :: (StackValue a) => LuaState -> String -> Either Int a

The next pair of operations is "callfunc" and "callproc". They both call a Lua function passing to it arbitrary number of arguments. The only difference is that "callfunc" returns and "callproc" omits the return value of Lua function called:

callfunc :: (StackValue x1, x2 ... xn, a) =>
            LuaState -> String -> x1 -> x2 ... xn -> Either Int a
callproc :: (StackValue x1, x2 ... xn) =>
            LuaState -> String -> x1 -> x2 ... xn -> IO Int

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

register :: (StackValue x1, x2 ... xn, a) =>
            LuaState -> String -> (x1 -> x2 ... xn -> {IO} a) -> IO Int

where {IO} means that the IO specifier is optional here. n>=0, i.e. register/callfunc/callproc may also register/call functions having no arguments.


5 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.


6 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


6.1 [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.

6.2 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

6.3 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?

6.4 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.


7 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