Kontent qismiga oʻtish

Modul:Fun

Vikipediya, erkin ensiklopediya

funktsional dasturlashda qo'llaniladigan ba'zi meta-funksiyalar. Hujjatlar uchun Vikilug‘atdagi Module:funga qarang.


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