Lemur

functional-1.0.lua

Sep 9th, 2014
316
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.26 KB | None | 0 0
  1. -- Functional Library
  2. --
  3. -- @version 1.0
  4. --
  5. -- @file    origin: functional.lua, now: underscore.lua
  6. -- @author  Shimomura Ikkei and expanded by Brandon Weaver
  7. -- @date    2005/05/18, 2014/09/09
  8. --
  9. -- @brief    porting several convenience functional utilities form Haskell,Python etc..
  10.  
  11. -- map(list, function)
  12. -- e.g: map({1,2,3}, double)    -> {2,4,6}
  13. function map(list, fn)
  14.   local newList = {}
  15.   for i,v in pairs(list) do newList[i] = fn(v) end
  16.   return newList
  17. end
  18.  
  19. -- filter(list, function)
  20. -- e.g: filter({1,2,3,4}, is_even) -> {2,4}
  21. function filter(list, fn)
  22.   local newList= {}
  23.   for i,v in pairs(list) do
  24.     if fn(v) then newList[i]=v end
  25.   end
  26.   return newList
  27. end
  28.  
  29. -- head(table)
  30. -- e.g: head({1,2,3}) -> 1
  31. function head(list)
  32.   return list[1]
  33. end
  34.  
  35. -- tail(table)
  36. -- e.g: tail({1,2,3}) -> {2,3}
  37. --
  38. -- XXX This is a BAD and ugly implementation.
  39. -- should return the address to next porinter, like in C (arr+1)
  40. function tail(list)
  41.   if table.getn(list) < 1 then
  42.     return nil
  43.   else
  44.     local newList = {}
  45.     local listSize = table.getn(list)
  46.     local i = 2
  47.     while (i <= listSize) do
  48.       table.insert(newList, i-1, list[i])
  49.       i = i + 1
  50.     end
  51.      return newList
  52.   end
  53. end
  54.  
  55. -- foldr(function, default_value, table)
  56. -- e.g: foldr(op.mul, 1, {1,2,3,4,5}) -> 120
  57. function foldr(fn, val, list)
  58.   for i,v in pairs(list) do val = fn(val, v) end
  59.   return val
  60. end
  61.  
  62. -- reduce(list, function)
  63. -- e.g: reduce({1,2,3,4}, op.add) -> 10
  64. function reduce(list, fn)
  65.   return foldr(fn, head(list), tail(list))
  66. end
  67.  
  68. -- curry(f,g)
  69. -- e.g: printf = curry(io.write, string.format)
  70. --          -> function(...) return io.write(string.format(unpack(arg))) end
  71. function curry(f,g)
  72.   return function (...)
  73.     return f(g(unpack(arg)))
  74.   end
  75. end
  76.  
  77. -- bind1(fn, binding_value_for_1st)
  78. -- bind2(fn, binding_value_for_2nd)
  79. -- @brief
  80. --      Binding argument(s) and generate new function.
  81. -- @see also STL's functional, Boost's Lambda, Combine, Bind.
  82. -- @examples
  83. --      local mul5 = bind1(op.mul, 5) -- mul5(10) is 5 * 10
  84. --      local sub2 = bind2(op.sub, 2) -- sub2(5) is 5 -2
  85. function bind1(fn, val1)
  86.   return function (val2)
  87.     return fn(val1, val2)
  88.   end
  89. end
  90.  
  91. function bind2(fn, val2) -- bind second argument.
  92.   return function (val1)
  93.     return fn(val1, val2)
  94.   end
  95. end
  96.  
  97. -- is(checker_function, expected_value)
  98. -- @brief
  99. --      check function generator. return the function to return boolean,
  100. --      if the condition was expected then true, else false.
  101. -- @example
  102. --      local is_table = is(type, "table")
  103. --      local is_even = is(bind2(math.mod, 2), 1)
  104. --      local is_odd = is(bind2(math.mod, 2), 0)
  105. is = function(check, expected)
  106.   return function (...)
  107.     if (check(unpack(arg)) == expected) then
  108.       return true
  109.     else
  110.       return false
  111.     end
  112.   end
  113. end
  114.  
  115. -- op table.
  116. -- @see also python's op module.
  117. op = {
  118.   mod = math.mod;
  119.   pow = math.pow;
  120.   add = function(n,m) return n + m end;
  121.   sub = function(n,m) return n - m end;
  122.   mul = function(n,m) return n * m end;
  123.   div = function(n,m) return n / m end;
  124.   gt  = function(n,m) return n > m end;
  125.   lt  = function(n,m) return n < m end;
  126.   eq  = function(n,m) return n == m end;
  127.   le  = function(n,m) return n <= m end;
  128.   ge  = function(n,m) return n >= m end;
  129.   ne  = function(n,m) return n ~= m end;
  130.   -- additional ops (Brandon)
  131.   _or   = function(n,m) return n or m end;
  132.   _nor  = function(n,m) return not n or m end;
  133.   _and  = function(n,m) return n and m end;
  134.   _xor  = function(n,m) return (n or m) and not (n and m) end;
  135.   _xnor = function(n,m) return not ((n or m) and not (n and m)) end;
  136.   _nand = function(n,m) return not n and m end;
  137.  
  138. }
  139.  
  140. -- enumFromTo(from, to)
  141. -- e.g: enumFromTo(1, 10) -> {1,2,3,4,5,6,7,8,9}
  142. -- TODO How to lazy evaluate in Lua? (thinking with coroutine)
  143. enumFromTo = function (from,to)
  144.   local newList = {}
  145.   local step = bind2(op[(from < to) and "add" or "sub"], 1)
  146.   local val = from
  147.   while val <= to do
  148.     table.insert(newList, table.getn(newList)+1, val)
  149.     val = step(val)
  150.   end
  151.   return newList
  152. end
  153.  
  154. -- make function to take variant arguments, replace of a table.
  155. -- this does not mean expand the arguments of function took,
  156. -- it expand the function's spec: function(list) -> function(...)
  157. function expand_args(fn)
  158.   return function(...) return fn(arg) end
  159. end
  160.  
  161. -------------------
  162.  
  163. -- Additions by Brandon Weaver
  164. -- Heavily inspired by Unix and Ruby
  165.  
  166. -- dotimes(number, function)
  167. -- see Ruby's Fixnum#times
  168. function do_times(n, fn)
  169.   for i = 0, n do fn(i) end
  170. end
  171.  
  172. -- pipe(initial_value, functions...)
  173. -- see Unix's pipe
  174. function pipe(...)
  175.   local value = head(arg)
  176.   local tail  = tail(arg)
  177.  
  178.   for i, v in ipairs(tail) do value = v(value) end
  179.  
  180.   return value
  181. end
  182.  
  183. -- alias for filter
  184. function select(list, fn)
  185.   return filter(list, fn)
  186. end
  187.  
  188. -- Opposite of select
  189. function reject(list, fn)
  190.   local newList= {}
  191.   for i,v in pairs(list) do
  192.     if not fn(v) then newList[i] = v end
  193.   end
  194.   return newList
  195. end
  196.  
  197. -- Finds a value in a table, returns false if not present
  198. function find(list, fn)
  199.   for i, v in pairs(list) do
  200.     if fn(v) then return v end
  201.   end
  202.  
  203.   return false
  204. end
  205.  
  206. -- Runs a function on each element without explicitly modifying it
  207. function each(list, fn)
  208.   for i, v in pairs(list) do fn(v) end
  209.  
  210.   return list
  211. end
  212.  
  213. -- Checks to see that all are true by a function
  214. function all_are(list, fn)
  215.   return reduce(op._and, map(fn,list))
  216. end
  217.  
  218. -- Opposite of all_are
  219. function none_are(list, fn)
  220.   return not all_are(list, fn)
  221. end
  222.  
  223. -- Alias for find
  224. function any_are(list, fn)
  225.   return find(list, fn)
  226. end
  227.  
  228. -- Partitions an array based on a function, returns two arrays, true and false
  229. function partition(list, fn)
  230.   local true_table  = {}
  231.   local false_table = {}
  232.  
  233.   local partitioner_fn = function(entity)
  234.     if fn(entity) then
  235.       table.insert(true_table, table.getn(true_table)+1, entity)
  236.     else
  237.       table.insert(false_table, table.getn(false_table)+1, entity)
  238.     end
  239.   end
  240.  
  241.   each(partitioner_fn, list)
  242.  
  243.   return {true_table, false_table}
  244. end
  245.  
  246. -- Uses Luas pattern matcher to 'grep' for strings
  247. function grep(pattern, list)
  248.   local pattern_fn = function(str) return string.find(str, pattern) end
  249.  
  250.   return select(pattern_fn, list)
  251. end
Advertisement
Add Comment
Please, Sign In to add comment