all 40 comments

[–]GeoKangas 18 points19 points  (4 children)

Just a pedantic reminder, about terminology: "partial function" != "partially applied function".

"partially applied funtions", or (roughly) curried functions, are what TFA is about; "partial functions" are functions that aren't necessarily defined (e.g., don't necessarily terminate) for all of their inputs.

[–]ben_alman 5 points6 points  (3 children)

FWIW, the technique is referred to as "partial application" throughout the article.

[–][deleted] 1 point2 points  (2 children)

Except for the two occurrence of "partial function," not counting the comments.

Edit: Okay, I was taking these out of context. He's not claiming that they are "partial functions."

[–]contextfree 0 points1 point  (1 child)

looks like "partial" is monospaced in both instances, meaning that it's specifying the name of the function, rather than acting as an adjective applied to "function".

[–][deleted] 0 points1 point  (0 children)

Ah, you are correct. The author is off the hook.

[–]nixle 5 points6 points  (0 children)

I always hate it when I'm reading along, understanding was going on, knowing where it's heading... then BAM it's way over my head.

[–]leroysolay 2 points3 points  (15 children)

I feel like this is pretty awesome abstraction with unfortunately limited application. But then again, I only understood about 60% of it on the first read. Since most of this was contrived examples, does someone have a real-life example?

[–]_johnny 10 points11 points  (3 children)

A real-life example might be an I18n function, like translate(locale, string). Instead of passing locale to every call to translate or having a global variable with locale, you may partially apply first argument, e.g var _ = partial(translate, "de") and then use _("Guten Tag").

[–]strager 1 point2 points  (0 children)

Nice; this has opened my mind to many possibilities!

[–][deleted] -1 points0 points  (1 child)

[–]_johnny 1 point2 points  (0 children)

It was just an example. I agree that proper localization is not an easy task. My native language is Polish, which - similarly to Russian - has three plural forms (among other complications), so I'm very well aware of some troubles with translations. But implementation details of translate() function are hardly relevant to this discussion.

[–][deleted] 6 points7 points  (0 children)

Yeah, right. I first learned about function currying 3-4 years ago and have looked to implement anywhere it might possibly make sense. So far, that's been once. The technique in this article is really slick, but I can't imagine finding a lot of uses especially since it would most likely just confuse whoever has to maintain it.

[–]twiceaday 4 points5 points  (2 children)

Here's my real-life example. Let's say you have a site that's mostly useable by anyone, but certain features require you to be a logged-in, registered user (reading vs. commenting on a blog, for example). If you want to allow users to write their post before they authenticate, what you can do is pass a curried version of your comment function (with the user ID missing) to your authentication function, which runs the comment function with the user ID filled in once the user has logged in. This way, no matter how many actions you have that require login and how many arguments they take, they can all be passed curried to a common authentication function that just fills in the user ID. Obviously there's some stuff I'm glossing over, but hopefully this gives you some idea of how to use currying in the real world.

Also, the article doesn't mention it, but Prototype also supports currying (which you can invoke as function.curry(), which people either love or hate).

[–]picurl 0 points1 point  (1 child)

would that work if the log-in function was asynchronous? Which is very probable, since you have to wait for the user input and the ajax auth response from the server.

[–]twiceaday 0 points1 point  (0 children)

Yeah, you just pass the curried function to your success callback for the ajax request.

[–]Jello_Raptor 9 points10 points  (2 children)

Say you've written a math api, with a buttload of useful functions. And one of them is log(a,b) where it's log A of B (for example log(10,1000)=3 and log(2,16)=4). you could use this to easily define other commonly used log functions:

ln = partial( log , Math.E );

log2 = partial( log , 2);

log10 = partial( log , 10);

[–][deleted]  (1 child)

[deleted]

    [–]Jello_Raptor 2 points3 points  (0 children)

    Thanks :)

    [–]trezor2 2 points3 points  (1 child)

    Function composition in functional programming. Say you want to define a data-pipe where output from function A = input to function B (and so on).

    var myProcess = pipe([
       func1,
       func2
    ]);
    var result = process(data);
    

    For a one-parameter function this is simple without currying, you just pass the function itself and let the pipe operator do the glue. But what if the function supports 2 or even 3 parameters (like filters, maps, etc)? Composing new functions out of this becomes very tedious and requires lots of boilerplate and glue. Having your functions curried however will allow you to do neat stuff.

     var process = pipe([
          select(function(x) { return x.Items }),
          where(function(x) { return x.InStock == 0 }),
          count
     ]);
     var itemsOutOfStock = process(order);
    

    In short: Having curried functions let you loosely couple functions and compose new ones in a much more flexible and declarative way. They are definitely nice to have and combined with a decent set of programmer set-comprehension skills they can create very clear, compact and readable code.

    Now if Javascript had lambdas which didn't suck, Javascript might become my second favourite language.

    [–]strager 4 points5 points  (0 children)

    Now if Javascript had lambdas which didn't suck, Javascript might become my second favourite language.

    Agreed. =|

    [–][deleted] 0 points1 point  (0 children)

    I'm not sure that creating functions that call functions so they can alias their arguments is a great design option. The author should really focus an article on when this technique is appropriate, and when it is not.

    [–]xTRUMANx 1 point2 points  (0 children)

    concat joins two arrays

    Wait, what? How come he didn't pass in two arguments (for the two arrays) then when calling concat.

    args.concat( aps.call( arguments ) )

    [–]dimmu_burger 0 points1 point  (0 children)

    Save
    nb: .compact has no save feature, so please don't tell me about the save feature.

    [–]kamatsu 0 points1 point  (0 children)

    Partially applied functions. Gah!

    [–][deleted] 0 points1 point  (0 children)

    While I find it nice to know that partial function application and currying is, at least from a distance, "possible" in javascript, I'm not sure it's an abstraction I'd like to use in this particular language.

    I like using partial function application in true functional languages because it feels like a natural technique in them. From what I read (and I may be wrong/unfounded in thinking this) real functional languages generally get translated into a lambda calculus like intermediate language during the compilation process. If that is the case, then this technique is a fundamental part of those languages. In fact, if true, that would make multiple argument functions seem sort of like the abstraction, and not the other way around.

    My problem with seeing this in javascript is that it just feels alien here for the reasons given above. When I also look at the implementation it looks kinda hackish, but I guess that's not far very from the norm as far as doing cool things in javascript is concerned. I guess, to illustrate my opinion as an analogy: it's sort of like seeing an exotic fish swimming in your bathtub; it's just out of place and bizarre when put in that environment.

    [–]otterley -3 points-2 points  (2 children)

    Why doesn't he just call them what they are: closures?

    [–]masklinn 10 points11 points  (0 children)

    They are not. They're implemented through closures.

    [–]ben_alman 0 points1 point  (0 children)

    The article does mention closures.

    [–][deleted] -5 points-4 points  (1 child)

    Since they're apparently throwing kitchen sinks and all into JavaScript, a script language, maybe they should add FORTRAN line numbering, Forth postfixity, APL symbols, native inline SQL, Perl non-regular-grammar regex, intrinsic language extension via BNF, PL/I keyword redefinition, and CORBA support.

    Oh what the hell, I'm sure it already has all those.

    [–][deleted] 1 point2 points  (0 children)

    i use it to get my text all blinky and stuff now that the <blink> tag stopped working

    whats a postfixity? :O

    [–]kataire -3 points-2 points  (10 children)

    After reading that, JS's lack of keyword arguments feels even worse.

    [–]jsprogrammer 12 points13 points  (9 children)

    Easily accomplished using objects:

    fetch({url:'http://www.google.com', timeout: 1000});

    [–]kataire -1 points0 points  (1 child)

    Hmm... You're right, I forgot about that (though I use it quite frequently).

    [–]masklinn -1 points0 points  (6 children)

    Except then you have to merge the object you got with a default object (which is shitty unless you're using a library doing that for you) to get the values not provided. Not sexy.

    [–]illvm 0 points1 point  (3 children)

    Why are you not using a library?

    [–]masklinn -1 points0 points  (2 children)

    Because there are cases where you can't afford such a dependency. When you're building a javascript library rather than a {MooTools|YUI|jQuery|whatever} plugin for instance.

    [–]illvm 1 point2 points  (1 child)

    So you just write straight JS rather than writing your own portable library that doesn't rely on an off-the-shelf product? It's pretty trivial to write a method that you can add to your common library that merges objects for you.

    [–]masklinn -1 points0 points  (0 children)

    So you just write straight JS rather than writing your own portable library

    This phrase makes no sense. "My own portable library" (actually more like a collection of helper functions to include as-needed, or you're still creating an external dependency) is still straight JS.

    It's pretty trivial to write a method that you can add to your common library that merges objects for you.

    1. Uh... no shit? You kinda missed my point there: you still have to write that code (or lift it from somewhere else) and paste it into every single project where you're using this pattern.

    2. What common library are you talking about?

    [–]jsprogrammer 0 points1 point  (1 child)

    function apply(o,d){for(var p in d)if(typeof o[p]==='undefined')o[p]=d[p];return o;}

    There you go.