diff --git a/CHANGELOG.md b/CHANGELOG.md index 7487a63..63d31e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Added `_.array` * Added `_.clear` * Added `_.time` +* Added `_.before` ## 1.6.0 (14/04/17) diff --git a/doc/index.html b/doc/index.html index 11a9a6f..bace80a 100644 --- a/doc/index.html +++ b/doc/index.html @@ -395,12 +395,16 @@

Utility functions

Creates a constant function which returns the same output on every call. + memoize (f[, hash]) + Memoizes a given function by caching the computed result. + + once (f) Returns a version of f that runs only once. - memoize (f[, hash]) - Memoizes a given function by caching the computed result. + before (f, count) + Returns a version of f that will run no more than count times. after (f, count) @@ -3319,6 +3323,38 @@

Returns:

+ +
+ + memoize (f[, hash]) +
+
+ Memoizes a given function by caching the computed result. + Useful for speeding-up slow-running functions. If a hash function is passed, + it will be used to compute hash keys for a set of input values for caching. +
Aliased as cache + + +

Parameters:

+ + +

Returns:

+
    + + a new function +
+ + + +
@@ -3346,20 +3382,19 @@

Returns:

See also:

- - memoize (f[, hash]) + + before (f, count)
- Memoizes a given function by caching the computed result. - Useful for speeding-up slow-running functions. If a hash function is passed, - it will be used to compute hash keys for a set of input values for caching. -
Aliased as cache + Returns a version of f that will run no more than count times. Next calls will + keep yielding the results of the count-th call.

Parameters:

@@ -3367,9 +3402,8 @@

Parameters:

  • f a function
  • -
  • hash - a hash function, defaults to identity - (optional) +
  • count + a count
  • @@ -3380,6 +3414,11 @@

    Returns:

    +

    See also:

    +
    @@ -3411,7 +3450,8 @@

    Returns:

    See also:

    @@ -5035,7 +5075,7 @@

    Returns:

    generated by LDoc 1.4.6 -Last updated 2017-04-27 15:04:19 +Last updated 2017-04-27 15:26:55
    diff --git a/doc/topics/tutorial.md.html b/doc/topics/tutorial.md.html index 86572a9..1acd09f 100644 --- a/doc/topics/tutorial.md.html +++ b/doc/topics/tutorial.md.html @@ -1449,6 +1449,22 @@

    constant (value)

    +

    memoize (f, hash)

    + +

    Aliases: _.cache.

    + +

    Memoizes a slow-running function. It caches the result for a specific input, so that the next time the function is called with the same input, it will lookup the result in its cache, instead of running again the function body.

    + +
    +local function fibonacci(n)
    +  return n < 2 and n or fibonacci(n-1)+fibonacci(n-2)
    +end
    +local mem_fibonacci = _.memoize(fibonacci)
    +fibonacci(20) -- => 6765 (but takes some time)
    +mem_fibonacci(20) -- => 6765 (takes less time)
    +
    + +

    once (f)

    Produces a function that runs only once. Successive calls to this function will still yield the same input.

    @@ -1463,19 +1479,18 @@

    once (f)

    -

    memoize (f, hash)

    +

    before (f, count)

    -

    Aliases: _.cache.

    - -

    Memoizes a slow-running function. It caches the result for a specific input, so that the next time the function is called with the same input, it will lookup the result in its cache, instead of running again the function body.

    +

    Returns a version of f that will run no more than count times. Next calls will keep yielding the results of the (n-th)-1 call.

    -local function fibonacci(n)
    -  return n < 2 and n or fibonacci(n-1)+fibonacci(n-2)
    -end
    -local mem_fibonacci = _.memoize(fibonacci)
    -fibonacci(20) -- => 6765 (but takes some time)
    -mem_fibonacci(20) -- => 6765 (takes less time)
    +local function greet(someone) return 'hello '..someone end
    +local greetOnly3people = _.before(greet, 3)
    +greetOnly3people('John') -- => 'hello John'
    +greetOnly3people('Moe') -- => 'hello Moe'
    +greetOnly3people('James') -- => 'hello James'
    +greetOnly3people('Joseph') -- => 'hello James'
    +greetOnly3people('Allan') -- => 'hello James'
     
    @@ -2327,7 +2342,7 @@

    Import

    generated by LDoc 1.4.6 -Last updated 2017-04-27 15:04:19 +Last updated 2017-04-27 15:26:55
    diff --git a/doc/tutorial.md b/doc/tutorial.md index 5e9c6ce..2a481b5 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -1240,6 +1240,20 @@ pi(2) -- => 3.1415926535898 pi(math.pi) -- => 3.1415926535898 ```` +### memoize (f, hash) +*Aliases: `_.cache`*. + +Memoizes a slow-running function. It caches the result for a specific input, so that the next time the function is called with the same input, it will lookup the result in its cache, instead of running again the function body. + +```lua +local function fibonacci(n) + return n < 2 and n or fibonacci(n-1)+fibonacci(n-2) +end +local mem_fibonacci = _.memoize(fibonacci) +fibonacci(20) -- => 6765 (but takes some time) +mem_fibonacci(20) -- => 6765 (takes less time) +```` + ### once (f) Produces a function that runs only once. Successive calls to this function will still yield the same input. @@ -1253,18 +1267,18 @@ sq(4) -- => 1 sq(5) -- => 1 ```` -### memoize (f, hash) -*Aliases: `_.cache`*. +### before (f, count) -Memoizes a slow-running function. It caches the result for a specific input, so that the next time the function is called with the same input, it will lookup the result in its cache, instead of running again the function body. +Returns a version of `f` that will run no more than `count` times. Next calls will keep yielding the results of the (n-th)-1 call. ```lua -local function fibonacci(n) - return n < 2 and n or fibonacci(n-1)+fibonacci(n-2) -end -local mem_fibonacci = _.memoize(fibonacci) -fibonacci(20) -- => 6765 (but takes some time) -mem_fibonacci(20) -- => 6765 (takes less time) +local function greet(someone) return 'hello '..someone end +local greetOnly3people = _.before(greet, 3) +greetOnly3people('John') -- => 'hello John' +greetOnly3people('Moe') -- => 'hello Moe' +greetOnly3people('James') -- => 'hello James' +greetOnly3people('Joseph') -- => 'hello James' +greetOnly3people('Allan') -- => 'hello James' ```` ### after (f, count) diff --git a/moses.lua b/moses.lua index ba6d3b8..f3d484a 100644 --- a/moses.lua +++ b/moses.lua @@ -1290,23 +1290,6 @@ function _.identity(value) return value end -- @return a constant function function _.constant(value) return function() return value end end ---- Returns a version of `f` that runs only once. Successive calls to `f` --- will keep yielding the same output, no matter what the passed-in arguments are. --- It can be used to initialize variables. --- @name once --- @param f a function --- @return a new function --- @see after -function _.once(f) - local _internal = 0 - local _args = {} - return function(...) - _internal = _internal+1 - if _internal<=1 then _args = {...} end - return f(unpack(_args)) - end -end - --- Memoizes a given function by caching the computed result. -- Useful for speeding-up slow-running functions. If a `hash` function is passed, -- it will be used to compute hash keys for a set of input values for caching. @@ -1326,6 +1309,42 @@ function _.memoize(f, hash) end end +--- Returns a version of `f` that runs only once. Successive calls to `f` +-- will keep yielding the same output, no matter what the passed-in arguments are. +-- It can be used to initialize variables. +-- @name once +-- @param f a function +-- @return a new function +-- @see before +-- @see after +function _.once(f) + local _internal = 0 + local _args = {} + return function(...) + _internal = _internal+1 + if _internal <= 1 then _args = {...} end + return f(unpack(_args)) + end +end + +--- Returns a version of `f` that will run no more than `count` times. Next calls will +-- keep yielding the results of the count-th call. +-- @name before +-- @param f a function +-- @param count a count +-- @return a new function +-- @see once +-- @see after +function _.before(f, count) + local _internal = 0 + local _args = {} + return function(...) + _internal = _internal+1 + if _internal <= count then _args = {...} end + return f(unpack(_args)) + end +end + --- Returns a version of `f` that runs on the `count-th` call. -- Useful when dealing with asynchronous tasks. -- @name after @@ -1333,12 +1352,13 @@ end -- @param count the number of calls before `f` will start running. -- @return a new function -- @see once +-- @see before function _.after(f, count) local _limit,_internal = count, 0 return function(...) - _internal = _internal+1 - if _internal >= _limit then return f(...) end - end + _internal = _internal+1 + if _internal >= _limit then return f(...) end + end end --- Composes functions. Each passed-in function consumes the return value of the function that follows. diff --git a/moses_min.lua b/moses_min.lua index e6e27bb..bb67dcc 100644 --- a/moses_min.lua +++ b/moses_min.lua @@ -205,13 +205,15 @@ function bab.concat(dcb,_db,adb,bdb) local cdb=bab.map(dcb,function(ddb,__c)return tostring(__c)end)return _da(cdb,_db,adb or 1,bdb or#dcb)end;function bab.noop()return end;function bab.identity(dcb)return dcb end;function bab.constant(dcb)return function()return dcb end end -function bab.once(dcb)local _db=0;local adb={}return -function(...)_db=_db+1;if -_db<=1 then adb={...}end;return dcb(c_b(adb))end end -function bab.memoize(dcb,_db)local adb=_ca({},{__mode='kv'}) -local bdb=_db or bab.identity -return function(...)local cdb=bdb(...)local ddb=adb[cdb] -if not ddb then adb[cdb]=dcb(...)end;return adb[cdb]end end +function bab.memoize(dcb,_db) +local adb=_ca({},{__mode='kv'})local bdb=_db or bab.identity;return +function(...)local cdb=bdb(...)local ddb=adb[cdb]if not ddb then +adb[cdb]=dcb(...)end;return adb[cdb]end end;function bab.once(dcb)local _db=0;local adb={} +return function(...)_db=_db+1;if _db<=1 then adb={...}end +return dcb(c_b(adb))end end +function bab.before(dcb,_db) +local adb=0;local bdb={}return +function(...)adb=adb+1;if adb<=_db then bdb={...}end;return dcb(c_b(bdb))end end function bab.after(dcb,_db)local adb,bdb=_db,0;return function(...)bdb=bdb+1;if bdb>=adb then return dcb(...)end end end function bab.compose(...)local dcb=bab.reverse{...} diff --git a/spec/func_spec.lua b/spec/func_spec.lua index c0ad0b6..2803922 100644 --- a/spec/func_spec.lua +++ b/spec/func_spec.lua @@ -38,6 +38,60 @@ context('Utility functions specs', function() end) + context('memoize', function() + + local fib_time, fib_value, mfib_time, mfib_value + local fib, mfib + + before(function() + local function fib(n) + return n < 2 and n or fib(n-1)+fib(n-2) + end + local times = 10 + local mfib = _.memoize(fib) + fib_time = os.clock() + for i = 1, times do fib_value = (fib_value or 0)+fib(20) end + fib_time = (os.clock()-fib_time)*1000 + + mfib_time = os.clock() + for i = 1, times do mfib_value = (mfib_value or 0)+mfib(20) end + mfib_time = (os.clock()-mfib_time )*1000 + end) + + test('memoizes an expensive function by caching its results',function() + assert_true(mfib_time<=fib_time) + end) + + test('can take a hash function to compute an unique output for multiple args',function() + + local function hash(a,b) return (a^13+b^19) end + local function fact(a) return a <= 1 and 1 or a*fact(a-1) end + local diffFact = function(a,b) return fact(a)-fact(b) end + local mdiffFact = _.memoize(function(a,b) return fact(a)-fact(b) end,hash) + local times, rep = 100, 10 + + local time = os.clock() + for j = 1,times do + for ai = 1,rep do + for aj = 1,rep do diffFact(ai,aj) end + end + end + time = (os.clock()-time)*1000 + + local mtime = os.clock() + for j = 1,times do + for ai = 1,rep do + for aj = 1,rep do mdiffFact(ai,aj) end + end + end + mtime = (os.clock()-mtime)*1000 + + assert_true(mtime<=time) + + end) + + end) + context('once', function() test('returns a version of a function that runs once',function() @@ -53,61 +107,23 @@ context('Utility functions specs', function() end) end) + + context('before', function() - context('memoize', function() - - local fib_time, fib_value, mfib_time, mfib_value - local fib, mfib - - before(function() - local function fib(n) - return n < 2 and n or fib(n-1)+fib(n-2) - end - local times = 10 - local mfib = _.memoize(fib) - fib_time = os.clock() - for i = 1, times do fib_value = (fib_value or 0)+fib(20) end - fib_time = (os.clock()-fib_time)*1000 - - mfib_time = os.clock() - for i = 1, times do mfib_value = (mfib_value or 0)+mfib(20) end - mfib_time = (os.clock()-mfib_time )*1000 + test('returns a version of a function that runs no more than count-th calls',function() + local function say(something) return something end + local speak3times = _.before(say, 3) + assert_equal(speak3times('a'), 'a') + assert_equal(speak3times('b'), 'b') + assert_equal(speak3times('c'), 'c') + assert_equal(speak3times('d'), 'c') + assert_equal(speak3times('e'), 'c') + assert_equal(speak3times('f'), 'c') end) - test('memoizes an expensive function by caching its results',function() - assert_true(mfib_time<=fib_time) - end) - - test('can take a hash function to compute an unique output for multiple args',function() - - local function hash(a,b) return (a^13+b^19) end - local function fact(a) return a <= 1 and 1 or a*fact(a-1) end - local diffFact = function(a,b) return fact(a)-fact(b) end - local mdiffFact = _.memoize(function(a,b) return fact(a)-fact(b) end,hash) - local times, rep = 100, 10 - - local time = os.clock() - for j = 1,times do - for ai = 1,rep do - for aj = 1,rep do diffFact(ai,aj) end - end - end - time = (os.clock()-time)*1000 - - local mtime = os.clock() - for j = 1,times do - for ai = 1,rep do - for aj = 1,rep do mdiffFact(ai,aj) end - end - end - mtime = (os.clock()-mtime)*1000 - - assert_true(mtime<=time) - - end) - - end) - + end) + + context('after', function() test('returns a function that will respond on its count-th call',function()