Functional Library

lua-users home
wiki


 -- Functional Library

 --

 -- @file    functional.lua

 -- @author  Shimomura Ikkei

 -- @date    2005/05/18

 --

 -- @brief    porting several convenience functional utilities form Haskell,Python etc..

 -- map(function, table)

 -- e.g: map(double, {1,2,3})    -> {2,4,6}

 function map(func, tbl)

     local newtbl = {}

     for i,v in pairs(tbl) do

         newtbl[i] = func(v)

     end

     return newtbl

 end

 -- filter(function, table)

 -- e.g: filter(is_even, {1,2,3,4}) -> {2,4}

 function filter(func, tbl)

     local newtbl= {}

     for i,v in pairs(tbl) do

         if func(v) then

	     newtbl[i]=v

         end

     end

     return newtbl

 end

 -- head(table)

 -- e.g: head({1,2,3}) -> 1

 function head(tbl)

     return tbl[1]

 end



 -- tail(table)

 -- e.g: tail({1,2,3}) -> {2,3}

 --

 -- XXX This is a BAD and ugly implementation.

 -- should return the address to next porinter, like in C (arr+1)

 function tail(tbl)

     if table.getn(tbl) < 1 then

         return nil

     else

         local newtbl = {}

         local tblsize = table.getn(tbl)

         local i = 2

         while (i <= tblsize) do

             table.insert(newtbl, i-1, tbl[i])

             i = i + 1

         end

        return newtbl

     end

 end

 -- foldr(function, default_value, table)

 -- e.g: foldr(operator.mul, 1, {1,2,3,4,5}) -> 120

 function foldr(func, val, tbl)

     for i,v in pairs(tbl) do

         val = func(val, v)

     end

     return val

 end



 -- reduce(function, table)

 -- e.g: reduce(operator.add, {1,2,3,4}) -> 10

 function reduce(func, tbl)

     return foldr(func, head(tbl), tail(tbl))

 end

 -- curry(f,g)

 -- e.g: printf = curry(io.write, string.format)

 --          -> function(...) return io.write(string.format(unpack(arg))) end

 function curry(f,g)

     return function (...)

         return f(g(unpack(arg)))

     end

 end

 -- bind1(func, binding_value_for_1st)

 -- bind2(func, binding_value_for_2nd)

 -- @brief

 --      Binding argument(s) and generate new function.

 -- @see also STL's functional, Boost's Lambda, Combine, Bind.

 -- @examples

 --      local mul5 = bind1(operator.mul, 5) -- mul5(10) is 5 * 10

 --      local sub2 = bind2(operator.sub, 2) -- sub2(5) is 5 -2

 function bind1(func, val1)

     return function (val2)

         return func(val1, val2)

     end

 end

 function bind2(func, val2) -- bind second argument.

     return function (val1)

         return func(val1, val2)

     end

 end

 -- is(checker_function, expected_value)

 -- @brief

 --      check function generator. return the function to return boolean,

 --      if the condition was expected then true, else false.

 -- @example

 --      local is_table = is(type, "table")

 --      local is_even = is(bind2(math.mod, 2), 1)

 --      local is_odd = is(bind2(math.mod, 2), 0)

 is = function(check, expected)

     return function (...)

         if (check(unpack(arg)) == expected) then

             return true

         else

             return false

         end

     end

 end

 -- operator table.

 -- @see also python's operator module.

 operator = {

     mod = math.mod;

     pow = math.pow;

     add = function(n,m) return n + m end;

     sub = function(n,m) return n - m end;

     mul = function(n,m) return n * m end;

     div = function(n,m) return n / m end;

     gt  = function(n,m) return n > m end;

     lt  = function(n,m) return n < m end;

     eq  = function(n,m) return n == m end;

     le  = function(n,m) return n <= m end;

     ge  = function(n,m) return n >= m end;

     ne  = function(n,m) return n ~= m end;



 }

 -- enumFromTo(from, to)

 -- e.g: enumFromTo(1, 10) -> {1,2,3,4,5,6,7,8,9}

 -- TODO How to lazy evaluate in Lua? (thinking with coroutine)

 enumFromTo = function (from,to)

     local newtbl = {}

     local step = bind2(operator[(from < to) and "add" or "sub"], 1)

     local val = from

     while val <= to do

         table.insert(newtbl, table.getn(newtbl)+1, val)

         val = step(val)

     end

     return newtbl

 end

 -- make function to take variant arguments, replace of a table.

 -- this does not mean expand the arguments of function took,

 -- it expand the function's spec: function(tbl) -> function(...)

 function expand_args(func)

     return function(...) return func(arg) end

 end

Sample codes

 local product = bind1(reduce, operator.mul)

 local sum = expand_args(bind1(reduce, operator.add))



 -- @see Python: fact=lambda num: reduce((lambda n,m: n*m), xrange(num,0,-1))

 -- @see Haskell: fact = (foldr (*) 1) . (enumFromTo 1)

 local factorial = curry(product,bind1(enumFromTo,1))


See also: LuaFunctors
RecentChanges · preferences
edit · history
Last edited February 18, 2009 2:44 pm GMT (diff)