
But – A way to pass along a callback with just a single argument - bevacqua
https://github.com/bevacqua/but
======
bevacqua
There's also `butt` if you have more complicated needs. Feel free to use it.

[https://github.com/bevacqua/butt](https://github.com/bevacqua/butt)

~~~
dyscrete
Why not allow an optional 2nd argument that defaults to 1 on your `but`
library to do this?

~~~
aaronem
Why complicate things? If it means so much to you, you can just

    
    
      var butt = require('butt');
      var but = function(fun) {
        return butt(fun, 1);
      };
    

or even

    
    
      var but = function(fun) {
        return function(arg) {
          return fun(arg);
        };
      };

------
kemitchell
Sigh ...

    
    
      module.exports = function (fn) {
        return function (first) {
          fn(first);
        };
      };

------
chingjun
Can anyone explain to me why I couldn't write

    
    
      n.forEach(console.log);
    
    

Just tested on Chrome, it gives me an error

    
    
      TypeError: Illegal invocation

~~~
nilved
When you use `console.log` that way it gets `this` set to `null`. When you
call `console.log("hello")`, `this` is set to `console`. Your code would work
if you set an explicit `this`.

    
    
        n.forEach(console.log.bind(console));
    

I don't think there's any reason for this library to exist after you
understand `this` semantics but I may be missing something.

e: was, in fact, missing something. Apologies for the disparaging comment, see
replies.

~~~
dyscrete
Well it's not just about `this` but the arguments to pass to console rather.
In this case:

    
    
        n.forEach(console.log.bind(console));
    

forEach is passing console all of its callback arguments, resulting in logging
of keys, values, and array.

EDIT: Forgot array

~~~
nilved
Ah, I understand. It reminds me of how the `cut` function could be used in
Scheme.

------
escape_goat

         function butter (){                                                                                                                                                                                                                                                                                      
           fn=arguments[0];                                                                                                                                                                                                                                                                                    
           return function(){                                                                                                                                                                                                                                                                                  
             var args = [];                                                                                                                                                                                                                                                                                     
             for( var n=1; n<arguments.length; n++ ) {                                                                                                                                                                                                                                                           
                args.push(arguments[n]);                                                                                                                                                                                                                                                                          
              };                                                                                                                                                                                                                                                                                                 
            return fn.apply(this,args)                                                                                                                                                                                                                                                                          
           }                                                                                                                                                                                                                                                                                                  
         }
    
    

_edit: I know my loop is totally anachronistic, but I 'm short on time for
testing this._

~~~
aaronem

      function butter(fun, count) {
        count = count || 1;
        if (count < 1) {
          throw new Error('Can't butter no toast');
        }
        return function() {
          return fun.apply(this, Array.prototype.slice.call(arguments, 0, count));
        }
      }

~~~
escape_goat
This is a dumb question, but I feel like maybe I'm failing to pick up on
something with respect to the necessity of the count parameter. It doesn't
seem like it should be necessary, but both 'butt' and your version here use
it. What is it for?

~~~
aaronem
It specifies how many arguments the returned function should take; in my
implementation, it defaults to 1 (so you can use it like "but"), but accepts
other values (so you can use it like "butt").

The reason why it's necessary to specify how many arguments are of interest is
because

Of course, since this is just common or garden partial application in a
language with first-class functions and a liberal attitude toward signatures,
it could be trivially generalized thus:

    
    
      function partial(fun) {
        var applied = Array.prototype.slice.call(arguments, 1);
        return function() {
          var args = applied
            // clone the already applied args, so we don't mistakenly modify when we...
            .slice()
            // ...tack on the args we received in this function's call
            .concat(Array.prototype.slice.call(arguments));
          return fun.apply(this, args);
        };
      }
    
      var addThreeNumbers = function(a, b, c) {
        return a + b + c;
      };
    
      var onePlusTheseTwo = partial(addThreeNumbers, 1);
    
      var threePlusThisOne = partial(onePlusTheseTwo, 2);
    
      assert(addThreeNumbers(1, 2, 3) === 6);
      assert(onePlusTheseTwo(2, 3) === 6);
      assert(threePlusThisOne(3) === 6);
      // -> all true
    

It only looks like wizardry if you're not used to dealing with higher-order
functions, wherein I think is meant to lie the joke, if any.

~~~
escape_goat
I don't encounter higher-order functions very often, and I certainly am not
mentally flexible with them. Nonetheless, I have heard of partial application,
yes. I understood what the count parameter was _doing_.

What I was having trouble understanding was why it was being used;
specifically, why 'but' would have a strict arity of one in the first place,
and why a second function (specifying arity) would be necessary. It doesn't
follow very clearly from the examples given at all.

 _edit: ...was this whole thing actually a joke? I thought he was serious._

~~~
aaronem
Oh! Sorry, no, that's because ECMAScript (Javascript)'s historical baggage and
lax attitude toward arity produce a combinatorial explosion of stupidity.

See, you can't just

    
    
      ['1', '2', '3'].map(parseInt)
    

because:

0) All Javascript functions are variadic; the signature specified at
definition time is largely advisory, and has semantic meaning only in that the
language will automatically declare and bind named arguments. Arguments named
in a function's signature, but not passed at call time, are undefined;
arguments not named in a function's signature, but passed at call time, are
not automatically bound to named variables, but can be accessed via the
_arguments_ binding, which is a unique object magically bound within a
function's scope, but which will be overridden by a named argument "arguments"
if one exists in the signature,

and

1) Array.map and friends pass their callbacks three arguments: the value of
the element, the _index_ of the element in the array being mapped over, _and_
a reference to the _entire_ array being mapped over,

and

2) Number.parseInt requires one argument, the value to cast to integer, and
accepts an optional second argument, specifying a radix between 2 and 36
inclusive.

So our naïve mapping above expands to the following series of calls:

    
    
      parseInt('1', 0, ['1', '2', '3']);
      // -> 1
      parseInt('2', 1, ['1', '2', '3']);
      // -> NaN
      parseInt('3', 2, ['1', '2', '3']);
      // -> NaN
    

tl;dr: None of this would be necessary in a language whose collection methods
did sane things. Since Javascript is not such a language, this is what we have
to do.

 _...I 'm not actually sure this whole thing was a joke, but it reads to me a
little like it might've been written with the sort of smirk you tend to see
academic FP purists directing at industry engineers._

------
nescalante
Extremely powerful library

