1

I want to understand how to use _.compose, and for example turn something like this:

url.substr(url.indexOf('?')) 

into composition, something maybe like:

var c = _.compose(String.substr, String.indexOf('?'))
c(url)

upd. Sorry for maybe asking really stupid question, but I don't get the way it suppose to work. Why this:

c = _.compose('abcd'.indexOf)
c('c')  // returns 5.. wtf?
iLemming
  • 34,477
  • 60
  • 195
  • 309
  • That's not plain (functor) composition that you want to do there. It's more like an applicative or monad. – Bergi Jul 07 '14 at 22:29
  • So, you're saying it means exactly what? – iLemming Jul 07 '14 at 22:29
  • That you cannot use `compose` if the `url` is used twice in that expression. – Bergi Jul 07 '14 at 22:30
  • I don't get how this thing works... Why for example `c = _.compose('abcd'.indexOf); c('c')` returns 5? – iLemming Jul 07 '14 at 22:42
  • @Agzam: because 'c' is the fifth letter of "Object"... ;) – dandavis Jul 07 '14 at 22:48
  • 1
    @Agzam: It actually does work in strict mode. In sloppy mode however, that is equivalent to `String.prototype.indexOf.call(window, 'c')` which is equivalent to `(window+"").indexOf('c')`. Notice that it does not make any sense to call `compose` on a single function, btw. – Bergi Jul 07 '14 at 22:52
  • compose() is good for when you have functions that take one argument and return one value, like c=_.compose( alert, Function.call.bind([].pop), JSON.parse, unescape); c("%5B%22hello%22%5D") – dandavis Jul 07 '14 at 22:54

1 Answers1

4

No. Function composition is

  substr(indexOf(url))
= compose(substr, indexOf)(url)

what you need is an Applicative actually which features

  substr(url, indexOf(url)) // actually substr(url)(indexOf(url))
= ap(substr, indexOf)(url)

Luckily, implementations for that exist already, let's go with

function ap(f, g) {
    return function() {
        return f.apply(this, arguments)(g.apply(this, arguments));
    };
}

Next, we need a way to turn the methods of String.prototype into functions, like they already exist in Firefox. We can use bindbind for that purpose, which also has the benefit of returning (partially) curried functions.

var substr = Function.prototype.bind.bind(String.prototype.substr);
var indexOf = Function.prototype.bind.bind(String.prototype.indexOf);

You would use them like indexOf("abcd")("c") or substr("abcd")(2) now. Last but not least we need to flip the arguments of indexOf, so that we could use it like flippedIndexOf("c")("abcd") (and more importantly, get the flippedIndexOf("c") function on its own). So let's use

function flip(f) {
    return function(b) {
        return function(a) {
            return f(a)(b);
        };
    };
}

Now, we can do what you initially wanted:

var c = ap(substr, flip(indexOf)("?"));

Looks good, and actually works!


But probably this is not worth all the hazzle. Just go with

function c(url) { return url.substr(url.indexOf('?')); }

which everybody understands even if he has no Computer Science degree :-)

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375