<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3Amemoize</id>
	<title>Module:memoize - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3Amemoize"/>
	<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:memoize&amp;action=history"/>
	<updated>2026-04-05T19:05:14Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://linguifex.com/w/index.php?title=Module:memoize&amp;diff=474921&amp;oldid=prev</id>
		<title>Sware: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:memoize&amp;diff=474921&amp;oldid=prev"/>
		<updated>2025-11-04T17:47:20Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 17:47, 4 November 2025&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Sware</name></author>
	</entry>
	<entry>
		<id>https://linguifex.com/w/index.php?title=Module:memoize&amp;diff=474920&amp;oldid=prev</id>
		<title>wikt&gt;Theknightwho: Optimisations.</title>
		<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:memoize&amp;diff=474920&amp;oldid=prev"/>
		<updated>2025-05-12T02:18:06Z</updated>

		<summary type="html">&lt;p&gt;Optimisations.&lt;/p&gt;
&lt;a href=&quot;https://linguifex.com/w/index.php?title=Module:memoize&amp;amp;diff=474920&amp;amp;oldid=410664&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>wikt&gt;Theknightwho</name></author>
	</entry>
	<entry>
		<id>https://linguifex.com/w/index.php?title=Module:memoize&amp;diff=410664&amp;oldid=prev</id>
		<title>Sware: Created page with &quot;local format = string.format local select = select local unpack = unpack  ----- M E M O I Z A T I O N----- -- Memoizes a function or callable table. -- Supports any number of arguments and return values. -- If the optional parameter `simple` is set, then the memoizer will use a faster implementation, but this is only compatible with one argument and one return value. If `simple` is set, additional arguments will be accepted, but this should only be done if those argument...&quot;</title>
		<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:memoize&amp;diff=410664&amp;oldid=prev"/>
		<updated>2025-01-08T21:18:16Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;local format = string.format local select = select local unpack = unpack  ----- M E M O I Z A T I O N----- -- Memoizes a function or callable table. -- Supports any number of arguments and return values. -- If the optional parameter `simple` is set, then the memoizer will use a faster implementation, but this is only compatible with one argument and one return value. If `simple` is set, additional arguments will be accepted, but this should only be done if those argument...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local format = string.format&lt;br /&gt;
local select = select&lt;br /&gt;
local unpack = unpack&lt;br /&gt;
&lt;br /&gt;
----- M E M O I Z A T I O N-----&lt;br /&gt;
-- Memoizes a function or callable table.&lt;br /&gt;
-- Supports any number of arguments and return values.&lt;br /&gt;
-- If the optional parameter `simple` is set, then the memoizer will use a faster implementation, but this is only compatible with one argument and one return value. If `simple` is set, additional arguments will be accepted, but this should only be done if those arguments will always be the same.&lt;br /&gt;
&lt;br /&gt;
-- Sentinels.&lt;br /&gt;
local nil_, neg_0, pos_nan, neg_nan&lt;br /&gt;
&lt;br /&gt;
-- Certain values can&amp;#039;t be used as table keys, so they require sentinels as well: e.g. f(&amp;quot;foo&amp;quot;, nil, &amp;quot;bar&amp;quot;) would be memoized at memo[&amp;quot;foo&amp;quot;][nil_][&amp;quot;bar&amp;quot;][memo]. These values are:&lt;br /&gt;
	-- nil.&lt;br /&gt;
	-- -0, which is equivalent to 0 in most situations, but becomes &amp;quot;-0&amp;quot; on conversion to string; it also behaves differently in some operations (e.g. 1/a evaluates to inf if a is 0, but -inf if a is -0).&lt;br /&gt;
	-- NaN and -NaN, which are the only values for which n == n is false; they only seem to differ on conversion to string (&amp;quot;nan&amp;quot; and &amp;quot;-nan&amp;quot;).&lt;br /&gt;
local function get_key(input)&lt;br /&gt;
	-- nil&lt;br /&gt;
	if input == nil then&lt;br /&gt;
		if not nil_ then&lt;br /&gt;
			nil_ = {}&lt;br /&gt;
		end&lt;br /&gt;
		return nil_&lt;br /&gt;
	-- -0&lt;br /&gt;
	elseif input == 0 and 1 / input &amp;lt; 0 then&lt;br /&gt;
		if not neg_0 then&lt;br /&gt;
			neg_0 = {}&lt;br /&gt;
		end&lt;br /&gt;
		return neg_0&lt;br /&gt;
	-- Default&lt;br /&gt;
	elseif input == input then&lt;br /&gt;
		return input&lt;br /&gt;
	-- NaN&lt;br /&gt;
	elseif format(&amp;quot;%f&amp;quot;, input) == &amp;quot;nan&amp;quot; then&lt;br /&gt;
		if not pos_nan then&lt;br /&gt;
			pos_nan = {}&lt;br /&gt;
		end&lt;br /&gt;
		return pos_nan&lt;br /&gt;
	-- -NaN&lt;br /&gt;
	elseif not neg_nan then&lt;br /&gt;
		neg_nan = {}&lt;br /&gt;
	end&lt;br /&gt;
	return neg_nan&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Return values are memoized as tables of return values, which are looked up using each input argument as a key, followed by `memo`. e.g. if the input arguments were (1, 2, 3), the memo would be located at t[1][2][3][memo]. `memo` is always used as the final lookup key so that (for example) the memo for f(1, 2, 3), f[1][2][3][memo], doesn&amp;#039;t interfere with the memo for f(1, 2), f[1][2][memo].&lt;br /&gt;
local function get_memo(memo, n, nargs, key, ...)&lt;br /&gt;
	key = get_key(key)&lt;br /&gt;
	local next_memo = memo[key]&lt;br /&gt;
	if next_memo == nil then&lt;br /&gt;
		next_memo = {}&lt;br /&gt;
		memo[key] = next_memo&lt;br /&gt;
	end&lt;br /&gt;
	memo = next_memo&lt;br /&gt;
	return n == nargs and memo or get_memo(memo, n + 1, nargs, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Catch the function output values, and return the hidden variable arg (which is {...}, and available when a function has ...). We do this instead of catching the output in a table directly, because arg also contains the key &amp;quot;n&amp;quot;, which is equal to select(&amp;quot;#&amp;quot;, ...). i.e. it&amp;#039;s the number of arguments in ..., including any nils returned after the last non-nil value (e.g. select(&amp;quot;#&amp;quot;, nil) == 1, select(&amp;quot;#&amp;quot;) == 0, select(&amp;quot;#&amp;quot;, nil, &amp;quot;foo&amp;quot;, nil, nil) == 4 etc.). The distinction between nil and nothing affects some native functions (e.g. tostring() throws an error, but tostring(nil) returns &amp;quot;nil&amp;quot;), so it needs to be reconstructable from the memo.&lt;br /&gt;
local function catch_output(...)&lt;br /&gt;
	-- TODO uses arg; will not work if Scribunto is upgraded to Lua 5.2, 5.3, etc.&lt;br /&gt;
	return arg&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return function(func, simple)&lt;br /&gt;
	local memo&lt;br /&gt;
	return simple and function(...)&lt;br /&gt;
		local key = get_key(...)&lt;br /&gt;
		if not memo then&lt;br /&gt;
			memo = {}&lt;br /&gt;
		end&lt;br /&gt;
		local output = memo[key]&lt;br /&gt;
		if output == nil then&lt;br /&gt;
			output = func(...)&lt;br /&gt;
			if output ~= nil then&lt;br /&gt;
				memo[key] = output&lt;br /&gt;
				return output&lt;br /&gt;
			elseif not nil_ then&lt;br /&gt;
				nil_ = {}&lt;br /&gt;
			end&lt;br /&gt;
			memo[key] = nil_&lt;br /&gt;
			return nil&lt;br /&gt;
		elseif output == nil_ then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		return output&lt;br /&gt;
	end or function(...)&lt;br /&gt;
		local nargs = select(&amp;quot;#&amp;quot;, ...)&lt;br /&gt;
		if not memo then&lt;br /&gt;
			memo = {}&lt;br /&gt;
		end&lt;br /&gt;
		-- Since all possible inputs need to be memoized (including true, false and nil), the memo table itself is used as the key for the arguments.&lt;br /&gt;
		local _memo = nargs == 0 and memo or get_memo(memo, 1, nargs, ...)&lt;br /&gt;
		local output = _memo[memo]&lt;br /&gt;
		if output == nil then&lt;br /&gt;
			output = catch_output(func(...))&lt;br /&gt;
			_memo[memo] = output&lt;br /&gt;
		end&lt;br /&gt;
		-- Unpack from 1 to the original number of return values (memoized as output.n); unpack returns nil for any values not in output.&lt;br /&gt;
		return unpack(output, 1, output.n)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;/div&gt;</summary>
		<author><name>Sware</name></author>
	</entry>
</feed>