Skip to content

Instantly share code, notes, and snippets.

@echiesse
Last active June 20, 2023 07:41
Show Gist options
  • Save echiesse/9365c19a020b24fa1950a2367b53f7f5 to your computer and use it in GitHub Desktop.
Save echiesse/9365c19a020b24fa1950a2367b53f7f5 to your computer and use it in GitHub Desktop.
Lua implementation of Maybe Monad.
-- The Maybe Monad:
local NOTHING = { val = nil }
maybe = {}
maybe.__index = maybe
-- Constructors:
maybe.just = function(val)
local obj = setmetatable({ val = val }, maybe)
return obj
end
setmetatable(NOTHING, maybe)
maybe.nothing = function()
return NOTHING
end
maybe.fromVal = function(val)
if val == nil then
return maybe.nothing()
else
return maybe.just(val)
end
end
-- Monad implementation:
maybe.bind = function(self, f)
if self == NOTHING then
return NOTHING
else
return f(self.val)
end
end
maybe.__mul = maybe.bind
maybe.pure = maybe.just
-- Utilities:
maybe.isNothing = function(self)
return self == NOTHING
end
function printMaybe(maybeObj)
print(showMaybe(maybeObj))
end
function showMaybe(maybeObj)
if maybeObj == maybe.nothing() then
return 'Nothing'
else
return 'Just ' .. tostring(maybeObj.val)
end
end
--##############################################################################
-- Monadic helpers for string operations:
maybeStr = {}
function maybeStr.wrap(f, ...)
local args = {...}
local ret = function(s)
local res = f(s, unpack(args))
if res == nil then
return maybe.nothing()
else
return maybe.just(res)
end
end
return ret
end
maybeStr.match = function(pat) return maybeStr.wrap(string.match, pat) end
--##############################################################################
-- Usage example:
maybeLen = maybe.just('abacate') -- Just 'abacate'
:bind(maybeStr.wrap(string.match, '([ab]+)')) -- Just 'aba'
:bind(maybeStr.wrap(string.gsub, 'b', '')) -- Just 'aa'
:bind(maybeStr.wrap(string.len)) -- Just 2
printMaybe(maybeLen)
maybeLen = maybe.nothing() -- Nothing
:bind(maybeStr.wrap(string.match, '([ab]+)')) -- Nothing
:bind(maybeStr.wrap(string.gsub, 'a', '')) -- Nothing
:bind(maybeStr.wrap(string.len)) -- Nothing
printMaybe(maybeLen)
maybeLen = maybe.just('abacate') -- Just 'abacate'
:bind(maybeStr.wrap(string.match, '(%d+)')) -- Nothing
:bind(maybeStr.wrap(string.gsub, 'b', '')) -- Nothing
:bind(maybeStr.wrap(string.len)) -- Nothing
printMaybe(maybeLen)
maybeLen = maybe.just('abacate') -- Just 'abacate'
* maybeStr.match('([abc]+)') -- Just 'abaca'
* maybeStr.wrap(string.gsub, 'b', '') -- Just 'aaca'
* maybeStr.wrap(string.len) -- Just 4
printMaybe(maybeLen)
maybeLen = maybe.just('abacate') -- Just 'abacate'
* function(s) return maybe.fromVal(string.match(s, '([abc]+)')) end -- Just 'abaca'
* function(s) return maybe.fromVal(string.gsub(s, 'b', '')) end -- Just 'aaca'
* function(s) return maybe.just(#s) end -- Just 4
printMaybe(maybeLen)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment