--
-- Simple Variant Records in Lua. Basically equivalent to algebraic data types.
-- In this version, they're not opaque. For best results, do not touch innards.
--
-- SPDX-FileCopyrightText: Chris Pressey, the original author of this work, has dedicated it to the public domain.
-- For more information, please refer to <https://unlicense.org/>
-- SPDX-License-Identifier: Unlicense
--
--
-- config is a table mapping tags to arrays of field names.
-- (arrays in Lua are number-keyed tables.)
--
function make_vrecord(config)
return {
maker = function(tag)
local fields = config[tag]
if not fields then
error("Undefined tag: " .. tag)
end
return function(...)
local num_args = select("#", ...)
if num_args ~= #fields then
error(
"Arity error: expected " .. tostring(#fields) ..
" for " .. tag .. ", got " .. tostring(num_args)
)
end
return {
tag = tag,
field_values = {...}
}
end
end,
case = function(obj, cases)
local tag = obj.tag
local field_values = obj.field_values
local fields = config[tag]
if not fields then
error("Undefined tag: " .. tostring(tag))
end
if #fields ~= #field_values then
error("Arity error")
end
local sel = cases[tag] or cases.otherwise
if not sel then
error("No case for tag: " .. tag)
end
return sel(table.unpack(obj.field_values))
end
}
end
--
-- Example
--
demo1 = function()
local List = make_vrecord({
null = {},
cons = {"head", "tail"}
})
local cons = List.maker("cons")
local null = List.maker("null")()
local dump
dump = function(list)
List.case(list, {
cons = function(head, tail)
print(head)
dump(tail)
end,
null = function()
end,
otherwise = function(ooo)
print("Not a list: " .. tostring(oo))
end
})
end
local abcs = cons("a", cons("b", cons("c", null)))
dump(abcs)
end
--demo1()