author: niplav, created: 2022-01-08, modified: 2022-01-08, language: english, status: in progress, importance: 2, confidence: likely
Solutions to the book “Programming in Lua” by Roberto Ierusalimschy.
function fact(n)
    elseif n==0 then
        return 1
    else
        return n * fact(n-1)
    end
end
print("enter a number:")
a=io.read("*n")
print(fact(a))
For a script that loads a library the dofile option is probably preferable, since then there is no need to deal with the different ways different platforms handle flags, when using lua interactively, the '-l' option is nicer, since one needs to type less.
Actually, from the top of my head, I really can't. But apparently, Haskell does it, which is weird, since Lua and Haskell have pretty different lineages afaik.
Valid identifiers from the list: ___, _end, End, NULL
Invalid identifiers: end, until?, nil
#!/usr/bin/lua
print(arg[0])
Then, update the permissions (on a unix-based system):
$ chmod 0755 ex_5.lua
The result of the expression type(nil)==nil is false, since the type
of type(nil) is string, and the string "nil" is not equal to the
value nil.
Invalid numerals: .e12, 0.0e, 0xABFG, FFFF, 0x
Valid numerals (with value): .0e12 -> 0.0, 0x12 -> 18, 0xA ->
10, 0xFFFFFFFF -> 4294967295, 0x1P10 -> 1024, 0.1e1 -> 1.0,
0x0.1p1 -> 0.125
12.7 can't be represented by
(n*12.7)/2^m
but 5.5 can be represented by
11/2^1
a="<![CDATA[\n  Hello world\n]]>"
b=[=[
<![CDATA[
  Hello world
]]>]=]
One good way to format the sequence of bytes would be to display it in a
string with escaped bytes in hexadecimal format, split into several lines
with "\z". By doing this problems with line length can be avoided and
performance is probably not very bad, considering that computers handle
byte sequences considerably well. Readability can, but should not be a
problem, since when dealing with arbitrary byte sequences the value in
hexadecimal is used more frequently than the ASCII value.
a={}
a.a=a
a.a.a.a evaluates to the table a the first a is a pointer to the
table a, the other as are all keys the expression can be rewritten as
a["a"]["a"]["a"]
a.a.a.a=3
Now the value for the key "a" is 3 in the table a, so a.a is 3,
and a.a.a is not indexable, since 3 has no field called "a". So Lua
prints an error message.
-10 2
-9 0
-8 1
-7 2
-6 0
-5 1
-4 2
-3 0
-2 2
-1 1
0 0
1 1
2 2
3 0
4 1
5 2
6 0
7 1
8 2
9 0
10 1
2^3^4=2^(3^4)=1.4178e+24
2^-3^4=(2^(-(3^4))=4.1359e-25
function polyeval(a, x)
    local res=0
    for i=1, #a do
        res=res+a[i]*x^(i-1)
    end
    return res
end
function polyeval(a, x)
    local res=0
    for i=1, #a do
        res=res*x
        res=res+a[i]
    end
    return res
end
function isbool(v)
    return v==true or v==false
end
The parentheses are not necessary, since not binds stronger than
and, and and binds stronger than or. However, the parentheses are
probably still a good idea, since they make the expression easier to
read and understand.
monday  sunday  sunday
One way to initialize the table would be to use the square bracket
notation. Associating the escape sequence "\a" with the literal bell
character would be done like this:
{["\\a"]="\a"}
This would be done for every escape sequence.
In Lua there is no switch/case statement, so elseif is a necessary (albeit not sufficient) replacement.
Preferred method is the first one, since it doesn't deal with limits and makes an infinite loop clear from the beginning.
while true do end
for i=0, math.huge do end
for i=2, 1, 0 do end
repeat until false
repeat-until is a construct similar to do-while in C, a construct which is also used rarely there. Apparently, in C only 5% of loops in C code are do-while loops. However, repeat-until can be useful to avoid initializing a variable the same way it is incremented in the loop, saving one line. It makes elegant solutions easier, but not much beyond that, so it could be left out easily.
local z = 0
local c
repeat
    c = io.read()
    if c == '0' then z=z+1 end
    print(z)
until c == nil
if z % 2 == 0 then
    print('ok')
else
    print('not ok')
end
Jumping out of a function would jump into the scope of a local variable, which is not possible (per definition) in Lua.
This would also cause problems in a function calling itself and jumping back into itself (or two different functions calling each other recursively), since there would be no good way to determine whether the goto would simply jump inside the function or outside into a previous call of itself.
The program would first print:
10
9
8
7
6
5
4
3
2
1
and then return an anonymous function that jumps to the end of getlabel() and return 0.
function concat(...)
    local args={...}
    local r=""
    for i, v in ipairs(args) do
        r=r..v
    end
    return r
end
function printarr(arr)
    print(table.unpack(arr))
end
function allbutone(...)
    local r={}
    local args=table.pack(...)
    for i=2, args.n do
        r[i-1]=args[i]
    end
    return table.unpack(r)
end
function combi(t, n)
    local arg={}
    local res={}
    local save={}
    if n<=0 then
        return {{}}
    end
    for k, v in ipairs(t) do save[k]=v end
    while #save>0 do
        local last=save[#save]
        save[#save]=nil
        for k, v in ipairs(save) do table.insert(arg, v) end
        local tmp=combi(arg, n-1)
        arg={}
        for i=1, #tmp do table.insert(tmp[i], last) end
        for k, v in ipairs(tmp) do table.insert(res, v) end
    end
    return res
end
function comb(t)
    local res={}
    for i=1, #t do
        tmp=combi(t, i)
        for k, v in ipairs(tmp) do table.insert(res, tmp[k]) end
    end
    return res
end
function integral(f)
    return function(x, y)
        local i, res, eps
        res=0; eps=0.001
        for i=x, y, eps do
            res=res+f(i)*eps
        end
        return res
    end
end
function newpoly(t)
    return function(x)
        local res=0
        for i=1, #t do
            res=res+t[i]*x^(#t-i)
        end
        return res
    end
end
n=100000
function f()
    print(n)
    n=n-1
    if n<0 then
        return nil
    else
        return "i=1;"
    end
end
load(f)()
function room1()
    local move=io.read()
    if move=="south" then room3()
    elseif move=="east" then room2()
    else
        print("invalid move")
        room1()
    end
end
function room2()
    local move=io.read()
    if move=="south" then room4()
    elseif move=="west" then room1()
    else
        print("invalid move")
        room2()
    end
end
function room3()
    local move=io.read()
    if move=="north" then room1()
    elseif move=="east" then room4()
    else
        print("invalid move")
        room3()
    end
end
function room4()
    print("Congrats, asshat. You won.")
end
room1()
function fromto(n, m)
    return fromit, {m}, n-1
end
function fromit(t, v)
    if v<t[1] then
        return v+1
    else
        return nil
    end
end
function fromto(n, m, s)
    return fromit, {m, s}, n-s
end
function fromit(t, v)
    if v+t[2]<=t[1] then
        return v+t[2]
    else
        return nil
    end
end
function uniquewords()
    local line=io.read()
    local wordtable={}
    local pos=1
    wordtable[""]=1
    return function()
        local str=""
        local s, e
        repeat
            s, e=string.find(line, "%w+", pos)
            if s then
                pos=e+1
                str=str.sub(line, s, e)
            else
                line=io.read()
                pos=1
            end
        until not line or wordtable[str]~=1
        wordtable[str]=1
        return (line and str) or nil
    end
end
function substrings(s)
    local len, pos
    len=0
    pos=1
    return function()
        if pos+len>#s then
            pos=pos+1
            len=0
        end
        if pos>#s then
            return nil
        else
            local str=string.sub(s, pos, pos+len)
            len=len+1
            return str
        end
    end
end
s is definitely a string, c can be a string or a function
function loadwithprefix(s, c)
    return load(function ()
        local t
        if s then
            t=s
            s=nil
        elseif type(c)=="string" then
            t=c
            c=nil
        elseif type(c)=="function" then
            t=c()
        end
        return t
    end)
end
function multiload(...)
    local t=table.pack(...)
    local i=1
    return load(function ()
        local res
        if i>#t then
            return nil
        end
        if type(t[i])=="string" then
            i=i+1
            return t[i-1]
        end
        while not res and i<=#t do
            res=t[i]()
            i=i+1
        end
        return res
    end)
end
The two functions have nearly the same speed.
function stringrep_n(n)
    local res=[[    s=...
    local r=""
]]
    if n>0 then
        while n>1 do
            if n%2~=0 then res=res .. "\tr=r .. s\n" end
            res=res .. "\ts=s .. s\n"
            n=math.floor(n/2)
        end
        res=res .. "\tr=r .. s\n"
    end
    res=res .. "\treturn r\n"
    return load(res)
end
Shamelessly stolen (years later, I don't know where from, though :-D):
function f()
    count = 0
    function g()
        count = count + 1
        if count == 2 then debug.sethook() end
        error()
    end
    debug.sethook(g, "r")
end
with
pcall(pcall, f)
returns false, nil.
function combgen(t, n, r, i)
    local idx=i or 1
    local res=r or {}
    if n<=0 then
        coroutine.yield(res)
    else
        for j=idx, #t-n do
            res[n]=t[j]
            combgen(t, n-1, res, j+1)
        end
    end
end
function combinations(t, n)
    return coroutine.wrap(function() combgen(t, n) end)
end
socket=require("socket")
function download(host, file)
    local c=assert(socket.connect(host, 80))
    local count=0
    c:send("GET " .. file .. " HTTP/1.0\r\n\r\n")
    while true do
        local s, status=receive(c)
        count=count+#s
        if status=="closed" then break end
    end
    c:close()
    print(file, count)
end
function receive(connection)
    connection:settimeout(0)
    local s, status, partial=connection:receive(2^10)
    if status=="timeout" then
        coroutine.yield(connection)
    end
    return s or partial, status
end
function get(host, file)
    local co=coroutine.create(function()
    download(host, file)
    end)
    table.insert(threads, co)
end
function dispatch()
    local i=1
    local timedout={}
    while true do
        if threads[i]==nil then
            if threads[1]==nil then break end
            i=1
            timedout={}
        end
        local status, res=coroutine.resume(threads[i])
        if not res then
            table.remove(threads, i)
        else
            i=i+1
            timedout[#timedout+1]=res
            if #timedout==#thredas then
                socket.select(timedout)
            end
        end
    end
end
threads={}
function transfer(cr)
    coroutine.yield(cr)
end
function dispatch(b)
    nr=coroutine.create(b)
    while nr~=nil do
        nr=coroutine.resume(nr)
    end
end
local N=8
local function isplaceok(a, n, c)
    for i=1, n-1 do
        if (a[i]==c) or
           (a[i]-i==c-n) or
           (a[i]+i==c+n) then
            return false
        end
    end
    return true
end
local function printsolution(a)
    for i=1, N do
        for j=1, N do
            io.write(a[i]==j and "X" or "-", " ")
        end
        io.write("\n")
    end
    io.write("\n")
    os.exit()
end
local function addqueen(a, n)
    if n>N then
        printsolution(a)
    else
        for c=1, N do
            if isplaceok(a, n, c) then
                a[n]=c
                addqueen(a, n+1)
            end
        end
    end
end
addqueen({}, 1)
local N=8
function permgen(a, n)
        n=n or #a
        if n<=1 then
                coroutine.yield(a)
        else
                for i=1, n do
                        a[n], a[i]=a[i], a[n]
                        permgen(a, n-1)
                        a[n], a[i]=a[i], a[n]
                end
        end
end
function permutations(a)
        return coroutine.wrap(function() permgen(a) end)
end
local function isplaceok(a, n, c)
        for i=1, n-1 do
                if (a[i]==c) or
                   (a[i]-i==c-n) or
                   (a[i]+i==c+n) then
                        return false
                end
        end
        return true
end
local function printsolution(a)
        for i=1, N do
                for j=1, N do
                        io.write(a[i]==j and "X" or "-", " ")
                end
                io.write("\n")
        end
        io.write("\n")
end
for q in permutations({1, 2, 3, 4, 5, 6, 7, 8}) do
    local i=1
    while i<N+1 and isplaceok(q, i, q[i]) do i=i+1 end
    if i==N+1 then printsolution(q) end
end
local function allwords()
    local auxwords=function()
        for line in io.lines() do
            for word in string.gmatch(line, "%w+") do
                coroutine.yield(word)
            end
        end
    end
    return coroutine.wrap(auxwords)
end
local counter={}
for w in allwords() do
    if #w>=4 then
        counter[w]=(counter[w] or 0) + 1
    end
end
local words={}
for w in pairs(counter) do
    words[#words+1]=w
end
table.sort(words, function(w1, w2)
    return counter[w1]>counter[w2] or
        counter[w1]==counter[w2] and w1<w2
end)
for i=1, (tonumber(arg[1]) or 10) do
    print(words[i], counter[words[i]])
end
local N=3
function allwords()
    local line=io.read()
    local pos=1
    return function()
        while line do
            local s, e=string.find(line, "%w+", pos)
            if s then
                pos=e+1
                return string.sub(line, s, e)
            else
                line=io.read()
                pos=1
            end
        end
        return nil
    end
end
function prefix(p)
    local s=p[1]
    for i=2, #p do s=s .. " " .. p[i] end
    return s
end
function back(p)
    for i=1, N-1 do p[i]=p[i+1] end
end
local statetab={}
function insert(index, value)
    local list=statetab[index]
    if list==nil then
        statetab[index]={value}
    else
        list[#list+1]=value
    end
end
local MAXGEN=10000
local NOWORD="\n"
pf={}
for i=1, N do pf[i]=NOWORD end
for w in allwords() do
    insert(prefix(pf), w)
    back(pf)
    pf[N]=w
end
insert(prefix(pf), NOWORD)
for i=1, N do pf[i]=NOWORD end
for i=1, MAXGEN do
    local ls=statetab[prefix(pf)]
    local r=math.random(#ls)
    local nextword=ls[r]
    if nextword==NOWORD then return end
    io.write(nextword, " ")
    back(pf)
    pf[N]=nextword
end
It's stupid to set both values to 0. This just restores the first state.
queue={}
function queue.new()
    return {first=0, last=-1}
end
function queue.pushfirst(q, value)
    q[q.first]=value
    q.first=q.first+1
end
function queue.pushlast(q, value)
    q[q.last]=value
    q.last=q.last-1
end
function queue.popfirst(q)
    local first=q.first-1
    if q.last>first then error("queue is empty") end
    local value=q[first]
    q[first]=nil
    q.first=first
    if q.last>=q.first-1 then q.first=0; q.last=-1 end
    return value
end
function queue.poplast(q)
    local last=q.last+1
    if last>q.first then error("queue is empty") end
    local value=q[last]
    q[last]=nil
    q.last=last
    if q.last>=q.first-1 then q.first=0; q.last=-1 end
    return value
end
Using a closure for the allwords argument
local function allwords(f)
    local auxwords=function()
        for line in io.lines(f) do
            for word in string.gmatch(line, "%w+") do
                coroutine.yield(word)
            end
        end
    end
    return coroutine.wrap(auxwords)
end
local ignore={}
for w in allwords(arg[2] or "ignore") do
    ignore[w]=true
end
local counter={}
for w in allwords() do
    if not ignore[w] then
        counter[w]=(counter[w] or 0) + 1
    end
end
local words={}
for w in pairs(counter) do
    words[#words+1]=w
end
table.sort(words, function(w1, w2)
    return counter[w1]>counter[w2] or
        counter[w1]==counter[w2] and w1<w2
end)
for i=1, (tonumber(arg[1]) or 10) do
    print(words[i], counter[words[i]])
end
function name2node(graph, name)
    local node=graph[name]
    if not node then
        node={name=name, adj={}}
        graph[name]=node
    end
    return node
end
function readgraph(f)
    local graph={}
    for line in io.lines(f) do
        local namefrom, nameto, label=string.match(line, "(%S+)%s+(%S+)%s+(%d+)")
        local from=name2node(graph, namefrom)
        local to=name2node(graph, nameto)
        from.adj[to]=label
    end
    return graph
end
function findpath(curr, to, path, visited)
    path=path or {}
    visited=visited or {}
    if visited[curr] then
        return nil
    end
    visited[curr]=true
    path[#path+1]=curr
    if curr==to then
        return path
    end
    for node in pairs(curr.adj) do
        local p=findpath(node, to, path, visited)
        if p then return p end
    end
    path[#path]=nil
end
function printpath(path)
    for i=1, #path do
        print(path[i].name)
    end
end
dofile("ex_3.lua")
function dijkstra(g, s, e)
    local unvisited={}
    local dist={}
    local prev={}
    local start=g[s]
    local lst=g[e]
    local current=start
    for i, j in pairs(g) do unvisited[j]=true end
    for i, j in pairs(g) do dist[j]=math.huge end
    dist[start]=0
    while current~=lst do
        for to, l in pairs(current.adj) do
            if unvisited[to]==true then
                local ndist=dist[current]+l
                if dist[to]>ndist then
                    dist[to]=ndist
                    prev[to]=current
                end
            end
        end
        unvisited[current]=false
        current=lst
        for i, j in pairs(unvisited) do
            if j==true and dist[i]<dist[current] then
                current=i
            end
        end
    end
    return prev
end
g: the graphs: the name of the starting pointe: the name of the endpointfunction serialize(o, l)
    l=l or 1
    if type(o)=="number" then
        io.write(string.format("%a", o))
    elseif type(o)=="string" then
        io.write(string.format("%q", o))
    elseif type(o)=="table" then
        io.write("{\n")
        for k, v in pairs(o) do
            io.write(string.rep("\t", l))
            serialize(k, l+1)
            io.write("=")
            serialize(v, l+1)
            io.write(",\n")
        end
        io.write(string.rep("\t", l-1) .. "}")
        if l==1 then io.write("\n") end
    else
        error("cannot serialize a " .. type(o))
    end
end
function serialize(o, l)
    l=l or 1
    if type(o)=="number" then
        io.write(string.format("%a", o))
    elseif type(o)=="string" then
        io.write(string.format("%q", o))
    elseif type(o)=="table" then
        io.write("{\n")
        for k, v in pairs(o) do
            io.write(string.rep("\t", l) .. "[")
            serialize(k, l+1)
            io.write("] = ")
            serialize(v, l+1)
            io.write(",\n")
        end
        io.write(string.rep("\t", l-1) .. "}")
        if l==1 then io.write("\n") end
    else
        error("cannot serialize a " .. type(o))
    end
end
function serialize(o, l)
    l=l or 1
    if type(o)=="number" then
        io.write(string.format("%a", o))
    elseif type(o)=="string" then
        io.write(string.format("%q", o))
    elseif type(o)=="table" then
        io.write("{\n")
        for k, v in pairs(o) do
            io.write(string.rep("\t", l))
            if type(k)~="string" or not isidentifier(k) then io.write("[") end
            if type(k)=="string" and isidentifier(k) then io.write(k)
            else serialize(k, l+1) end
            if type(k)~="string" or not isidentifier(k) then io.write("]") end
            io.write(" = ")
            serialize(v, l+1)
            io.write(",\n")
        end
        io.write(string.rep("\t", l-1) .. "}")
        if l==1 then io.write("\n") end
    else
        error("cannot serialize a " .. type(o))
    end
end
function isidentifier(s)
    return string.match(s, "^[a-zA-Z_][a-zA-Z0-9_]*$")
end
function serialize(o, l)
    l=l or 1
    if type(o)=="number" then
        io.write(string.format("%a", o))
    elseif type(o)=="string" then
        io.write(string.format("%q", o))
    elseif type(o)=="table" then
        local i=1
        io.write("{\n")
        if o[i]~=nil then
            io.write(string.rep("\t", l))
            while o[i]~=nil do serialize(o[i]); io.write(", "); i=i+1 end
            io.write("\n")
        end
        for k, v in pairs(o) do
            if type(k)~="number" or k<1 or k>i then
                io.write(string.rep("\t", l))
                if type(k)~="string" or not isidentifier(k) then io.write("[") end
                if type(k)=="string" and isidentifier(k) then io.write(k)
                else serialize(k, l+1) end
                if type(k)~="string" or not isidentifier(k) then io.write("]") end
                io.write(" = ")
                serialize(v, l+1)
                io.write(",\n")
            end
        end
        io.write(string.rep("\t", l-1) .. "}")
        if l==1 then io.write("\n") end
    else
        error("cannot serialize a " .. type(o))
    end
end
function isidentifier(s)
    return string.match(s, "^[a-zA-Z_][a-zA-Z0-9_]*$")
end