pandastrike / fairmont

Functional (and) reactive programming library for JavaScript.
ISC License
49 stars 8 forks source link

curry doesn't work with async #53

Open automatthew opened 7 years ago

automatthew commented 7 years ago

curry relies on Function.length to to determine the number of arguments it needs to handle. async returns a proxying function with length 0.

Proposal to fix this: record the arglength of the function passed to async as a property on the function it returns.

In fairmont-helpers:

async = (g) ->

  if !(isGeneratorFunction g)
    throw new TypeError "#{g} is not a generator function"

  fn = (args...) ->
    self = this
    promise (resolve, reject) ->
      i = g.apply self, args
      f = -> i.next()
      do step = (f) ->
        try
          {done, value} = f()
        catch error
          reject error

        if done
          resolve value
        else
          follow value
          .then (value) -> step -> i.next value
          .catch (error) -> step -> i.throw error
  fn.asyncArgs = g.length
  fn

In fairmont-core:

curry = (f) ->
  g = (ax...) ->
    arglength = f.length || f.asyncArgs
    if ax.length >= arglength
      f ax...
    else
      switch arglength - ax.length
        when 1
          (x) -> f ax..., x
        when 2
          binary curry (x,y) -> f ax..., x, y
        when 3
          ternary curry (x,y,z) -> f ax..., x, y, z
        else (bx...) -> g ax..., bx...
automatthew commented 7 years ago

an alternative is to use new Function(str) to create a custom proxy.

http://jsperf.com/functions-with-custom-length

dyoder commented 7 years ago
  1. I'm loathe to add any more non-standard properties to things than absolutely necessary.
  2. We have this problem with a variety of combinators, not just async.
  3. Right now, this can be handled by simply setting unary, binary, or ternary.
  4. We could simply switch on g.length and return a function accordingly.
  5. We need to account for variadics, which is one reason (2) was appealing.