A Library in Lua
My third post, like the previous two, is related to "adventure" in different programming languages! I don't know how useful this kind of posts can be, but most likely it has its own fans (even a few) and it's interesting for me too...
Lua Programming Language
Since this post is not long in terms of content other than code, I will tell you a little about Lua!
Wikipedia says:
Lua (/ˈluːə/ LOO-ə; from Portuguese: lua [ˈlu(w)ɐ] meaning moon) is a lightweight, high-level, multi-paradigm programming language designed primarily for embedded use in applications. Lua is cross-platform, since the interpreter of compiled bytecode is written in ANSI C, and Lua has a relatively simple C API to embed it into applications.
And:
Lua originated in 1993 as a language for extending software applications to meet the increasing demand for customization at the time. It provided the basic facilities of most procedural programming languages, but more complicated or domain-specific features were not included; rather, it included mechanisms for extending the language, allowing programmers to implement such features. As Lua was intended to be a general embeddable extension language, the designers of Lua focused on improving its speed, portability, extensibility and ease-of-use in development.
Except for the last program that you will see in the next part of this article, almost the rest of the programs are also written in Teal (Lua, but its statically typed version)... I really liked its syntax, the facilities it offers and its good execution speed; but due to the inability to understand the logic of the code, and because it only relies on specified types, it gives ridiculous errors sometimes!
What Did I Make With It?
Lua Itself
Definitely the first one was Fizzbuzz!
io.write("Enter the starting point of the range: ")
startPoint = io.read("*n")
io.write("And the end point: ")
endPoint = io.read("*n")
for i = startPoint, endPoint do
if i % 15 == 0 then
print("FizzBuzz")
elseif i % 5 == 0 then
print("Buzz")
elseif i % 3 == 0 then
print("Fizz")
else
print(i)
end
end
To learn how to take user input, mathematical operators, and function declarations, writing a simple calculator program isn't a bad place to start...
local Calculator = {}
function Calculator:add(a, b)
return a + b
end
function Calculator:sub(a, b)
return a - b
end
function Calculator:mul(a, b)
return a * b
end
function Calculator:div(a, b)
return a / b
end
function Calculator:mod(a, b)
return a % b
end
while true do
io.write("A (a.k.a. first number): ")
local a = io.read("*n")
io.write("B (a.k.a. second number): ")
local b = io.read("*n")
print(a .. " + " .. b .. " = " .. Calculator:add(a, b))
print(a .. " - " .. b .. " = " .. Calculator:sub(a, b))
print(a .. " * " .. b .. " = " .. Calculator:mul(a, b))
print(a .. " / " .. b .. " = " .. Calculator:div(a, b))
print(a .. " % " .. b .. " = " .. Calculator:mod(a, b))
print()
end
A very simple linear search algorithm on the languages I knew (even just their names)...
local langs = {"Python", "Lua", "JavaScript", "Go[lang]", "Zig",
"C++", "C", "Rust", "TypeScript", "Ruby", "Julia",
"Clojure", "Scala", "Java", "Ada", "D", "Elixir",
"Elm", "OCaml", "C#", "F#", "Hack", "Groovy", "Kotlin",
"Swift", "MATLAB", "R", "Nim", "MoonScript", "Pascal",
"COBOL", "PHP", "PureScript", "Red", "Raku", "SQL",
"Solidity", "V", "Vala", "Fortran", "Gleam", "HTML(!)",
"CSS", "Farr", "Lisp", "Crystal", "Bash", "Chapel",
"Brainfuck", "JSFuck", "Assembly", "Dart", "LiveScript",
"Objective-C", "Perl", "Prolog", "SASS", "Smalltalk"}
local target = "MoonScript"
for i = 1, #langs do
if langs[i] == target then
print("Hooray! We found it at index " .. i .. ".")
os.exit(0)
end
end
print("Sorry, dude!")
Number guessing game with the ability to manipulate the difficulty level:
io.write("Enter the difficulty level: ")
local difficulty = io.read("*n")
if difficulty < 1 then
print("The difficulty level must be a positive number...")
os.exit(1)
end
math.randomseed(os.time())
local secretNumber = math.floor(math.random() * 10 ^ difficulty)
for i = 1, 3 do
io.write("Enter your " .. i .. " guess?! ")
local guess = io.read("*n")
if guess == secretNumber then
print("Hooray!")
os.exit(0)
elseif guess < secretNumber then
print("Greater...")
else
print("Smaller...")
end
end
print("Sorry, loser! The secret number was " .. secretNumber .. "!")
And something that can be very useful, especially for those who have experience working with the functional programming paradigm:
local DEBUG_MODE = arg[1] == "--debug-mode"
local Boost = {}
-- Checks if all elements in a table satisfy a condition.
-- @param {function} func - Function to check on each element.
-- @param {table} tbl - Table to check.
-- @returns {boolean} - True if all elements pass the check, false otherwise.
function Boost.all(func, tbl)
for _, e in ipairs(tbl) do
if not func(e) then
return false
end
end
return true
end
-- Tests the `Boost.all` function.
function Boost.testAll()
print("🤞 Testing `Boost.all` function...")
local inputTbl = { 2, 4, 6 }
local expectedResult = true
local result = Boost.all(
function(x)
return x % 2 == 0
end,
inputTbl
)
assert(
result == expectedResult,
(
"Result mismatch: " .. "Expected " .. tostring(expectedResult)
.. " but got " .. tostring(result) .. "!"
)
)
print("✅ Test passed successfully!")
end
-- Checks if any element in a table satisfies a condition.
-- @param {function} func - Function to check on each element.
-- @param {table} tbl - Table to check.
-- @returns {boolean} - True if any element passes the check, false otherwise.
function Boost.any(func, tbl)
for _, e in ipairs(tbl) do
if func(e) then
return true
end
end
return false
end
-- Tests the `Boost.any` function.
function Boost.testAny()
print("🤞 Testing `Boost.any` function...")
local inputTbl = { 1, 2, 3, 4, 5 }
local expectedResult = true
local result = Boost.any(
function(x)
return x % 2 == 0
end,
inputTbl
)
assert(
result == expectedResult,
(
"Result mismatch: " .. "Expected " .. tostring(expectedResult)
.. " but got " .. tostring(result) .. "!"
)
)
print("✅ Test passed successfully!")
end
-- Applies a function to each element of a table.
-- @param {function} func - Function to apply to each element.
-- @param {table} tbl - Table to map.
-- @returns {table} - New table with the results of applying func to each element.
function Boost.map(func, tbl)
local result = {}
for _, e in ipairs(tbl) do
table.insert(result, func(e))
end
return result
end
-- Tests the `Boost.map` function.
function Boost.testMap()
print("🤞 Testing `Boost.map` function...")
local inputTbl = { 0, 1, 2, 3, 4 }
local expectedTbl = { 0, 1, 4, 9, 16 }
local resultTbl = Boost.map(
function(x)
return x ^ 2
end,
inputTbl
)
assert(
#resultTbl == #expectedTbl,
(
"Length mismatch: " .. "Expected " .. #expectedTbl
.. " elements, but got " .. #resultTbl .. "!"
)
)
for i, v in ipairs(resultTbl) do
assert(
v == expectedTbl[i],
"Element mismatch at index " .. i .. "!"
)
end
print("✅ Test passed successfully!")
end
-- Filters elements of a table based on a condition.
-- @param {function} func - Function to filter elements.
-- @param {table} tbl - Table to filter.
-- @returns {table} - New table with elements that pass the filter.
function Boost.filter(func, tbl)
local result = {}
for _, e in ipairs(tbl) do
if func(e) then
table.insert(result, e)
end
end
return result
end
-- Tests the `Boost.filter` function.
function Boost.testFilter()
print("🤞 Testing `Boost.filter` function...")
local inputTbl = { 1, 2, 3, 4, 5, 6 }
local expectedTbl = { 2, 4, 6 }
local resultTbl = Boost.filter(
function(x)
return x % 2 == 0
end,
inputTbl
)
assert(
#resultTbl == #expectedTbl,
(
"Length mismatch: " .. "Expected " .. #expectedTbl
.. " elements, but got " .. #resultTbl .. "!"
)
)
for i, v in ipairs(resultTbl) do
assert(
v == expectedTbl[i],
"Element mismatch at index " .. i .. "!"
)
end
print("✅ Test passed successfully!")
end
-- Finds the first element in a table that satisfies a condition.
-- @param {function} func - Function to find an element.
-- @param {table} tbl - Table to find in.
-- @returns {*} - First element that passes the function, or nil if none.
function Boost.findFirst(func, tbl)
for _, e in ipairs(tbl) do
if func(e) then
return e
end
end
return nil
end
-- Tests the `Boost.findFirst` function.
function Boost.testFindFirst()
print("🤞 Testing `Boost.findFirst` function...")
local inputTbl = { 1, 2, 3, 4, 5 }
local expectedResult = 2
local result = Boost.findFirst(
function(x)
return x % 2 == 0
end,
inputTbl
)
assert(
result == expectedResult,
(
"Result mismatch: " .. "Expected " .. expectedResult
.. " but got " .. result .. "!"
)
)
print("✅ Test passed successfully!")
end
-- Reduces a table to a single output by applying a function cumulatively.
-- @param {function} func - Function to apply cumulatively to elements.
-- @param {table} tbl - Table to reduce.
-- @param {*} initial - Initial value for reduction.
-- @returns {*} - Result of reducing the table.
function Boost.reduce(func, tbl, initial)
local result = initial
for i = 1, #tbl do
result = func(result, tbl[i])
end
return result
end
-- Tests the `Boost.reduce` function.
function Boost.testReduce()
print("🤞 Testing `Boost.reduce` function...")
local inputTbl = { 1, 2, 3, 4, 5 }
local expectedResult = 15
local result = Boost.reduce(
function(a, b)
return a + b
end,
inputTbl,
0
)
assert(
result == expectedResult,
(
"Result mismatch: " .. "Expected " .. expectedResult
.. " but got " .. result .. "!"
)
)
print("✅ Test passed successfully!")
end
if DEBUG_MODE then
Boost.testAll()
print()
Boost.testAny()
print()
Boost.testMap()
print()
Boost.testFilter()
print()
Boost.testFindFirst()
print()
Boost.testReduce()
end
return Boost
In Teal
I have decided to put the codes here without explanation so that you can understand the syntax; but from the names of the functions, you can easily guess what they are about...
local function linearSearch(list: {number}, target: number): integer | nil
for i = 1, #list do
if list[i] == target then
return i
end
end
return nil
end
local list = {5, 1, 2, 3, 8, 9, 4}
local target = 8
print(linearSearch(list, target))
local function binarySearch(list: {number}, target: number): integer
local low, mid, high: integer, integer, integer = 0, 0, #list
while low <= high do
mid = math.ceil((low + high) / 2)
if list[mid] < target then
low = mid + 1
elseif list[mid] > target then
high = mid - 1
else
return mid
end
end
return -1
end
local list: {number} = {1, 2, 3, 4, 5, 6, 7, 8, 9}
local target: number = 4
print("List: " .. table.concat(list, ", ") .. " | Target: " .. target)
print("Index: " .. binarySearch(list, target))
list = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50}
target = 40
print("\nList: " .. table.concat(list, ", ") .. " | Target: " .. target)
print("Index: " .. binarySearch(list, target))
local function bubbleSort(list: {number}): {number}
for i = 1, #list do
for j = 1, #list - i do
if list[j] > list[j+1] then
local temp = list[j]
list[j] = list[j+1]
list[j+1] = temp
end
end
end
return list
end
print(table.concat(bubbleSort({6, 2, 8, 9, 3, 1}), ", "))
local function fakeNaturalLanguageProcessing(text: string): {string}
local categories: {string: {string}} = {
angry = {"angry", "mad", "upset", "frustrated", "irritated", "infuriated", "enraged", "outraged"},
happy = {"happy", "joyful", "cheerful", "delighted", "thrilled", "ecstatic", "elated", "jubilant"},
sad = {"sad", "depressed", "unhappy", "miserable", "melancholy", "despondent", "gloomy", "somber"},
surprised = {"surprised", "amazed", "astonished", "stunned", "shocked", "thunderstruck", "flabbergasted", "dumbfounded"},
fearful = {"fearful", "afraid", "scared", "terrified", "petrified", "apprehensive", "anxious", "nervous"}
}
local labels: {string} = {}
for category, words in pairs(categories) do
local count: integer = 0
for _, word in ipairs(words) do
if string.find(string.lower(text), word) then
count = count + 1
end
end
if count >= 2 then
table.insert(labels, category)
end
end
return labels
end
local text: string = [[
I was thrilled to hear the news, but my friend was terrified and scared.
She was so upset and angry that she started crying, feeling sad and miserable.
]]
local labels: {string} = fakeNaturalLanguageProcessing(text)
print(table.concat(labels, ", "))
Last Words
I don't know yet what I want to do with Lua in the future, but maybe later I want to make a game with it for smartphones that...
Useful links:
Subscribe to my newsletter
Read articles from Artin Mohammadi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Artin Mohammadi
Artin Mohammadi
A software developer who sometimes creates content — I'm very eager to get a deeper experience by implementing things from scratch.