lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I came up with a little Lua problem today, and I thought it would make
a fun puzzle for some of you.  (My solution is included at the end, so
if you want to play, stop reading when I tell you to stop!)

Consider this code:

  function multiplyAndAdd (a,b,c)  return a * b + c  end
  
  multiplyBySevenAndAdd = curry1(multiplyAndAdd,7)
  
  assert( multiplyAndAdd(7,8,9) == multiplyBySevenAndAdd(8,9) )
  
"Curry1" takes a function (eg multiplyAndAdd) and a value (eg 7).
It returns a function that is similar to the one it was passed, 
except that the returned function takes one fewer argument
(eg 2 instead of 3).  What used to be the first argument (eg "a")
is now "frozen" to the given value (eg 7).  Our curried function
above would be equivalent to:

  function multiplyBySevenAndAdd (b,c)  return 7 * b + c  end

"Curry1" is pretty easy to write, using 5.1's wacky ... operator:

  function curry1 (f,v)
    return function (...)  return f(v,...)  end
  end

Now, consider this generalization:

  multiplyBySevenAndAdd          = curry( multiplyAndAdd, 7       )
  multiplySevenByEightAndAdd     = curry( multiplyAndAdd, 7, 8    )
  multiplySevenByEightAndAddNine = curry( multiplyAndAdd, 7, 8, 9 )

  assert( multiplyAndAdd(7,8,9) == multiplyBySevenAndAdd(8,9)       )
  assert( multiplyAndAdd(7,8,9) == multiplySevenByEightAndAdd(9)    )
  assert( multiplyAndAdd(7,8,9) == multiplySevenByEightAndAddNine() )

"Curry" takes a function and an *arbitrary* number of values "n".  It
returns a function that is similar to the one it was passed, except
the returned function takes n fewer arguments.  What used to be the
first n arguments are "frozen" to the given values, as shown.

Challenge #1:  Write "curry".  (You may assume that none of the values
are nil, since nil and ... don't play nice together.)

Challenge #2:  Write "curry" without using any tables!  ;)

My solution follows, so stop reading if you're up for the challenges.

  :
  :
  :
  :
  :
  :
  :
  :
  :

  function curry (f,v,...)
    if v == nil then return f end
    return curry( curry1(f,v), ... )
  end
  
This is pretty elegant, but it requires one (tail) function call per
curried argument.  I'm curious whether it's possible to write a "curry"
that doesn't create all this indirection.  (And doesn't test the length
of { ... } and use explicit code for different lengths!)