2
\$\begingroup\$

Is doing something like this utilizing currying in a practical sense?

function processOneClickPurchase(item) {
    let context = { step: 0 }

    let addItemToCart = item => {
        let cart = getSession().cart
        cart.items.push(item)
        log('Cart items', cart.items)
        return cart
    }

    ...

    let purchase = generate([
        addItemToCart,
        makePurchase,
        processBilling,
        setupShipping,
        sendPurchaseAndShippingNotification,
    ], null, cleanup)

    return purchase(item)

    function generate(steps, before, after) {
        const takeStep = (incoming, outgoing) => {
            let message = {
                step: ++context.step,
                incoming: incoming,
                outgoing: outgoing
            };

            log('step #'+(context.step), message)

            return outgoing
        }
        const walk = value => {
            return steps.reduce((from, to) => {
                return takeStep(from, to(from))
            }, value)
        }

        (before && steps.push(before)) + (after && steps.push(after))

        return function invoke(state) {
            const hasItems = Array.isArray(state) || !(state = [state])
            const processed = state.map(walk)
            return hasItems ? processed : processed[0]
        }
    }
}

https://jsfiddle.net/f7mdak6z/25/

I realize there's algebra going on with currying and maybe this is nonsensical, so we're not talking rigid math concepts. However, it seems to me this pattern is rudimentary and it feels like an application of currying over an input to achieve an output. takeStep() almost seems like a monad, etc.

I think it would definitely start to sound like a fit if the methods passed to generate() simply modified the stream, and perhaps the takeStep() function handled side-effects.

\$\endgroup\$
  • \$\begingroup\$ Currying is converting a function taking n arguments into series of n-1 functions each taking 1 argument. For example, currying foo = (a, b, c) => ... would be foo = a => b => c => .... Maybe you could clarify to which function do you refer to. \$\endgroup\$ – morbusg Apr 6 at 17:47
  • 1
    \$\begingroup\$ What does this code accomplish? Please tell us, and also make that the title of the question, as per the How to Ask guidelines. Note that there is a return purchase(item) that doesn't make sense since it's not within a function — please ensure that you have included enough code for the question to make sense. \$\endgroup\$ – 200_success Apr 6 at 21:31
  • \$\begingroup\$ @morbusg I use steps instead of arguments for the n series of functions, and invoke() is being called over the series of functions. \$\endgroup\$ – Jared Farrish Apr 7 at 1:40
1
\$\begingroup\$

I take it here that you mean “algebra” to mean lambda calculus and by extension, combinatory logic.

The takeStep function is essentially (disregarding side-effects): $$ \lambda ab.b $$ in lambda calculus, or in JS in terms of identity (using Haskell Curry’s combinator naming):

I = a => a
K = a => b => a
KI = K(I)

So as the takeStep function is simply disregarding the first argument, and the walk function calling the second argument with the previous (/initial) value there and then, I’m wondering if you would really be after the B-combinator $$ \lambda fga.f(ga) $$ (or, as JS: B = f => g => a => f(g(a)), often named compose) with possibly the C-combinator $$ \lambda fab.fba $$ (C = f => a => b => f(b)(a)) for reversing the arguments (often named pipe or sequence for f => g => a => g(f(a))).

(I’m not sure if the commutativity of the functions or JS evaluation strategy plays a role here.)

Regarding currying, I wonder if you were thinking of partial application instead.

\$\endgroup\$
  • \$\begingroup\$ That's interesting, the compose part; my initial desire was to create a piped procedural that allowed an array of functional modifiers to be applied. The takeStep() is essentially a bridge observing both, mainly to keep the functions pure (saving to a store would be in the takeStep() method). I'll have to read through this a few times to get it, thank you for the response. \$\endgroup\$ – Jared Farrish Apr 9 at 16:24
  • \$\begingroup\$ A cleaner, updated version: jsfiddle.net/f7mdak6z/42 generate() is now coalesce() at the bottom. \$\endgroup\$ – Jared Farrish Apr 9 at 20:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.