<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.stiles.casa/index.php?action=history&amp;feed=atom&amp;title=Module%3AFun</id>
	<title>Module:Fun - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.stiles.casa/index.php?action=history&amp;feed=atom&amp;title=Module%3AFun"/>
	<link rel="alternate" type="text/html" href="https://wiki.stiles.casa/index.php?title=Module:Fun&amp;action=history"/>
	<updated>2026-04-07T12:36:09Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.2</generator>
	<entry>
		<id>https://wiki.stiles.casa/index.php?title=Module:Fun&amp;diff=7828&amp;oldid=prev</id>
		<title>imported&gt;Erutuon: fix filter</title>
		<link rel="alternate" type="text/html" href="https://wiki.stiles.casa/index.php?title=Module:Fun&amp;diff=7828&amp;oldid=prev"/>
		<updated>2019-09-17T21:55:38Z</updated>

		<summary type="html">&lt;p&gt;fix filter&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local p = {}&lt;br /&gt;
&lt;br /&gt;
local ustring = mw.ustring&lt;br /&gt;
local libraryUtil = require &amp;quot;libraryUtil&amp;quot;&lt;br /&gt;
local checkType = libraryUtil.checkType&lt;br /&gt;
local checkTypeMulti = libraryUtil.checkTypeMulti&lt;br /&gt;
&lt;br /&gt;
local iterableTypes = { &amp;quot;table&amp;quot;, &amp;quot;string&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
local _checkCache = {}&lt;br /&gt;
local function _check(funcName, expectType)&lt;br /&gt;
	if type(expectType) == &amp;quot;string&amp;quot; then&lt;br /&gt;
		return function(argIndex, arg, nilOk)&lt;br /&gt;
			return checkType(funcName, argIndex, arg, expectType, nilOk)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- Lua 5.1 doesn&amp;#039;t cache functions as Lua 5.3 does.&lt;br /&gt;
		local checkFunc = _checkCache[funcName]&lt;br /&gt;
			or function(argIndex, arg, expectType, nilOk)&lt;br /&gt;
				if type(expectType) == &amp;quot;table&amp;quot; then&lt;br /&gt;
					if not (nilOk and arg == nil) then&lt;br /&gt;
						return checkTypeMulti(funcName, argIndex, arg, expectType)&lt;br /&gt;
					end&lt;br /&gt;
				else&lt;br /&gt;
					return checkType(funcName, argIndex, arg, expectType, nilOk)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		_checkCache[funcName] = checkFunc&lt;br /&gt;
		return checkFunc&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Iterate over UTF-8-encoded codepoints in string.&lt;br /&gt;
local function iterString(str)&lt;br /&gt;
	local iter = string.gmatch(str, &amp;quot;[%z\1-\127\194-\244][\128-\191]*&amp;quot;)&lt;br /&gt;
	local i = 0&lt;br /&gt;
	local function iterator()&lt;br /&gt;
		i = i + 1&lt;br /&gt;
		local char = iter()&lt;br /&gt;
		if char then&lt;br /&gt;
			return i, char&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return iterator&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- funcName and startArg are for argument type-checking.&lt;br /&gt;
-- The varargs (...) can be either an iterator and its optional state and start&lt;br /&gt;
-- value, or an iterable type, in which case the function calls the appropriate&lt;br /&gt;
-- iterator generator function.&lt;br /&gt;
local function getIteratorTriplet(funcName, startArg, ...)&lt;br /&gt;
	local t = type(...)&lt;br /&gt;
	if t == &amp;quot;function&amp;quot; then&lt;br /&gt;
		return ...&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local first = ...&lt;br /&gt;
	checkTypeMulti(funcName, startArg, first, iterableTypes)&lt;br /&gt;
	if t == &amp;quot;string&amp;quot; then&lt;br /&gt;
		return iterString(first)&lt;br /&gt;
	elseif first[1] ~= nil then&lt;br /&gt;
		return ipairs(first)&lt;br /&gt;
	else&lt;br /&gt;
		return pairs(first)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.chain(func1, func2, ...)&lt;br /&gt;
	return func1(func2(...))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--	map(function(number) return number ^ 2 end,&lt;br /&gt;
--		{ 1, 2, 3 })									--&amp;gt; { 1, 4, 9 }&lt;br /&gt;
--	map(function (char) return string.char(string.byte(char) - 0x20) end,&lt;br /&gt;
--		&amp;quot;abc&amp;quot;)											--&amp;gt; { &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, &amp;quot;C&amp;quot; }&lt;br /&gt;
-- Two argument formats:&lt;br /&gt;
-- map(func, iterable)&lt;br /&gt;
-- map(func, iterator[, state[, start_value]])&lt;br /&gt;
-- func is a function that takes a maximum of two return values of the iterator&lt;br /&gt;
-- in reverse order. They are supplied in reverse order because the ipairs&lt;br /&gt;
-- iterator returns the index before the value, but the value is most often more&lt;br /&gt;
-- important than the index.&lt;br /&gt;
&lt;br /&gt;
-- Any need for map that retains original keys, rather than creating an array?&lt;br /&gt;
function p.map(func, keepOriginalKeys, ...)&lt;br /&gt;
	checkType(&amp;quot;map&amp;quot;, 1, func, &amp;quot;function&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local iter, state, start_value&lt;br /&gt;
	if type(keepOriginalKeys) == &amp;quot;boolean&amp;quot; then&lt;br /&gt;
		iter, state, start_value = getIteratorTriplet(&amp;quot;map&amp;quot;, 3, ...)&lt;br /&gt;
	else -- keepOriginalKeys is actually iterator or iterable.&lt;br /&gt;
		iter, state, start_value = getIteratorTriplet(&amp;quot;map&amp;quot;, 2, keepOriginalKeys, ...)&lt;br /&gt;
		keepOriginalKeys = false&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local result = {}&lt;br /&gt;
	if keepOriginalKeys then&lt;br /&gt;
		for val1, val2 in iter, state, start_value do&lt;br /&gt;
			result[val1] = func(val2, val1, state)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		local i = 0&lt;br /&gt;
		for val1, val2 in iter, state, start_value do&lt;br /&gt;
			i = i + 1&lt;br /&gt;
			result[i] = func(val2, val1, state)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
p.mapIter = p.map&lt;br /&gt;
&lt;br /&gt;
local function fold(func, result, ...)&lt;br /&gt;
	checkType(&amp;quot;fold&amp;quot;, 1, func, &amp;quot;function&amp;quot;)&lt;br /&gt;
	local iter, state, start_value = getIteratorTriplet(&amp;quot;fold&amp;quot;, 3, ...)&lt;br /&gt;
	for val1, val2 in iter, state, start_value do&lt;br /&gt;
		result = func(result, val2, val1, state)&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
p.fold = fold&lt;br /&gt;
&lt;br /&gt;
function p.count(func, ...)&lt;br /&gt;
	checkType(&amp;quot;count&amp;quot;, 1, func, &amp;quot;function&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	return fold(&lt;br /&gt;
		function (count, val)&lt;br /&gt;
			if func(val) then&lt;br /&gt;
				return count + 1&lt;br /&gt;
			end&lt;br /&gt;
			return count&lt;br /&gt;
		end,&lt;br /&gt;
		0,&lt;br /&gt;
		...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.forEach(func, ...)&lt;br /&gt;
	checkType(&amp;quot;forEach&amp;quot;, 1, func, &amp;quot;function&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local iter, state, start_value = getIteratorTriplet(&amp;quot;forEach&amp;quot;, 2, ...)&lt;br /&gt;
	for val1, val2 in iter, state, start_value do&lt;br /&gt;
		func(val2, val1, state)&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------&lt;br /&gt;
-- From http://lua-users.org/wiki/CurriedLua.&lt;br /&gt;
-- reverse(...) : take some tuple and return a tuple of elements in reverse order&lt;br /&gt;
--&lt;br /&gt;
-- e.g. &amp;quot;reverse(1,2,3)&amp;quot; returns 3,2,1&lt;br /&gt;
local function reverse(...)&lt;br /&gt;
	-- reverse args by building a function to do it, similar to the unpack() example&lt;br /&gt;
	local function reverseHelper(acc, v, ...)&lt;br /&gt;
		if select(&amp;quot;#&amp;quot;, ...) == 0 then&lt;br /&gt;
			return v, acc()&lt;br /&gt;
		else&lt;br /&gt;
			return reverseHelper(function() return v, acc() end, ...)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- initial acc is the end of the list&lt;br /&gt;
	return reverseHelper(function() return end, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.curry(func, numArgs)&lt;br /&gt;
	-- currying 2-argument functions seems to be the most popular application&lt;br /&gt;
	numArgs = numArgs or 2&lt;br /&gt;
	&lt;br /&gt;
	-- no sense currying for 1 arg or less&lt;br /&gt;
	if numArgs &amp;lt;= 1 then return func end&lt;br /&gt;
	&lt;br /&gt;
	-- helper takes an argTrace function, and number of arguments remaining to be applied&lt;br /&gt;
	local function curryHelper(argTrace, n)&lt;br /&gt;
		if n == 0 then&lt;br /&gt;
			-- kick off argTrace, reverse argument list, and call the original function&lt;br /&gt;
			return func(reverse(argTrace()))&lt;br /&gt;
		else&lt;br /&gt;
			-- &amp;quot;push&amp;quot; argument (by building a wrapper function) and decrement n&lt;br /&gt;
			return function(onearg)&lt;br /&gt;
				return curryHelper(function() return onearg, argTrace() end, n - 1)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- push the terminal case of argTrace into the function first&lt;br /&gt;
	return curryHelper(function() return end, numArgs)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
--	some(function(val) return val % 2 == 0 end,&lt;br /&gt;
--		{ 2, 3, 5, 7, 11 })						--&amp;gt; true&lt;br /&gt;
function p.some(func, ...)&lt;br /&gt;
	checkType(&amp;quot;some&amp;quot;, 1, func, &amp;quot;function&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local iter, state, start_value = getIteratorTriplet(&amp;quot;some&amp;quot;, 2, ...)&lt;br /&gt;
	for val1, val2 in iter, state, start_value do&lt;br /&gt;
		if func(val2, val1, state) then&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--	all(function(val) return val % 2 == 0 end,&lt;br /&gt;
--		{ 2, 4, 8, 10, 12 })					--&amp;gt; true&lt;br /&gt;
function p.all(func, ...)&lt;br /&gt;
	checkType(&amp;quot;some&amp;quot;, 1, func, &amp;quot;function&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local iter, state, start_value = getIteratorTriplet(&amp;quot;all&amp;quot;, 2, ...)&lt;br /&gt;
	for val1, val2 in iter, state, start_value do&lt;br /&gt;
		if not func(val2, val1, state) then&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.indexOf(func, ...)&lt;br /&gt;
	local iter, state, start_value = getIteratorTriplet(&amp;quot;indexOf&amp;quot;, 2, ...)&lt;br /&gt;
	&lt;br /&gt;
	if type(func) == &amp;quot;function&amp;quot; then&lt;br /&gt;
		for val1, val2 in iter, state, start_value do&lt;br /&gt;
			if func(val2, val1, state) then&lt;br /&gt;
				return val1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	&lt;br /&gt;
	-- func is actually value to search for.&lt;br /&gt;
	-- Not a great idea to combine these two separate functions.&lt;br /&gt;
	elseif func ~= nil then -- check for NaN?&lt;br /&gt;
		for val1, val2 in iter, state, start_value do&lt;br /&gt;
			if func == val2 then&lt;br /&gt;
				return val1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		error(&amp;quot;value to search for is nil&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.filter(func, ...)&lt;br /&gt;
	local check = _check &lt;br /&gt;
	checkType(&amp;quot;filter&amp;quot;, 1, func, &amp;quot;function&amp;quot;)&lt;br /&gt;
	&lt;br /&gt;
	local new_t = {}&lt;br /&gt;
	local new_i = 0&lt;br /&gt;
	local iter, state, start_value = getIteratorTriplet(&amp;quot;filter&amp;quot;, 2, ...)&lt;br /&gt;
	for val1, val2 in iter, state, start_value do&lt;br /&gt;
		if func(val2, val1, state) then&lt;br /&gt;
			new_i = new_i + 1&lt;br /&gt;
			new_t[new_i] = val1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return new_t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.range(low, high)&lt;br /&gt;
	low = low - 1&lt;br /&gt;
	return function ()&lt;br /&gt;
		if low &amp;lt; high then&lt;br /&gt;
			low = low + 1&lt;br /&gt;
			return low&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-------------------------------&lt;br /&gt;
-- Fancy stuff&lt;br /&gt;
local function capture(...)&lt;br /&gt;
	local vals = { ... }&lt;br /&gt;
	return function()&lt;br /&gt;
		return unpack(vals)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Log input and output of function.&lt;br /&gt;
-- Receives a function and returns a modified form of that function.&lt;br /&gt;
function p.logReturnValues(func, prefix)&lt;br /&gt;
	return function(...)&lt;br /&gt;
		local inputValues = capture(...)&lt;br /&gt;
		local returnValues = capture(func(...))&lt;br /&gt;
		if prefix then&lt;br /&gt;
			mw.log(prefix, inputValues())&lt;br /&gt;
			mw.log(returnValues())&lt;br /&gt;
		else&lt;br /&gt;
			mw.log(inputValues())&lt;br /&gt;
			mw.log(returnValues())&lt;br /&gt;
		end&lt;br /&gt;
		return returnValues()&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
p.log = p.logReturnValues&lt;br /&gt;
&lt;br /&gt;
-- Convenience function to make all functions in a table log their input and output.&lt;br /&gt;
function p.logAll(t)&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		if type(v) == &amp;quot;function&amp;quot; then&lt;br /&gt;
			t[k] = p.logReturnValues(v, tostring(k))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return t&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
----- M E M O I Z A T I O N-----&lt;br /&gt;
-- metamethod that does the work&lt;br /&gt;
-- Currently supports one argument and one return value.&lt;br /&gt;
local func_key = {}&lt;br /&gt;
local function callMethod(self, x)&lt;br /&gt;
	local output = self[x]&lt;br /&gt;
	if not output then&lt;br /&gt;
		output = self[func_key](x)&lt;br /&gt;
		self[x] = output&lt;br /&gt;
	end&lt;br /&gt;
	return output&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- shared metatable&lt;br /&gt;
local mt = { __call = callMethod }&lt;br /&gt;
&lt;br /&gt;
-- Create callable table.&lt;br /&gt;
function p.memoize(func)&lt;br /&gt;
	return setmetatable({ [func_key] = func }, mt)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;Erutuon</name></author>
	</entry>
</feed>