1

So, I was just thinking about how cool chaining is and how it makes things easier to read. With a lot of languages, when applying a bunch of functions to a variable, you'd write something like this:

i(h(g(f(x))))

And you have to read it from right-to-left or inner-most to outer-most. You apply f first, then g, and so forth. But if it were chained, it would look more like

x|f|g|h|i

And you could read it like a normal human being. So, my question is, there has to be some languages that do it that way, what are they? Is that what these fancy-pants functional programming languages do?


Because of this, I usually end up creating a whole bunch of temp variables so that I can split it onto separate lines and make it more readable:

a = f(x)
b = g(a)
c = h(b)
what_i_really_wanted_all_along = i(c)

Where's with my magical language, you could still split it onto different lines, if they're getting too long, without needing intervening variables:

x | f
  | g
  | h
  | i
mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • 1
    It's called "Function Composition". Please fix the question title. – S.Lott Nov 26 '10 at 02:14
  • @S.Lott: You can fix it if you feel it so necessary. I didn't know what it was called. Leaving it "incorrect" might help others find it easier so that they can learn what it actually *is* called. – mpen Nov 26 '10 at 02:17
  • You could help other people by rewriting the question to include the correct term as well as your guess at the correct term. Or you could refuse to be helpful. I wasn't confused, so I can't really clarify this. You, however, were confused, so you can help others by matching the correct term with your guess. – S.Lott Nov 26 '10 at 02:19
  • @S.Lott: The Haskell example you gave is backwards to what I described. I'm not entirely convinced this *is* what you call "functional composition". This sounds more like "fluent interface" like Michael said. – mpen Nov 26 '10 at 02:25

8 Answers8

5

Yes, with F# you have a pipeline operator |> (also called forward pipe operator, and you have a backward pipe <|).

You write it like: x |> f |> g |> h |> i

Check this blog post that gives a good idea of real life usage.

elmattic
  • 12,046
  • 5
  • 43
  • 79
  • Crazy... do you find that having both a forward and backwards pipe is useful in practice, or does it add to the confusion? Having to distinguish which way you're going? – mpen Nov 26 '10 at 02:21
  • Most of the time I use the forward pipe. Not so much the backward pipe. – elmattic Nov 26 '10 at 02:25
  • That blog post accurately describes the perks of piping that I was hoping to illustrate :) – mpen Nov 26 '10 at 03:02
3

It's not exclusive to functional programming, though it probably best implemented in functional languages, since the whole concept of function composition is squarely in the functional programming's domain.

For one thing, any language with object-oriented bent has chaining for methods which return an instance of the class:

obj.method1().method2().method3(); // JavaScript
MyClass->new()->f()->g()->i(); # Perl

Alternately, the most famous yet the least "programming-language" example of this chaining pattern would be something completely non-OO and non-functional ... you guessed it, pipes in Unix. As in, ls | cut -c1-4 | sort -n. Since shell programming is considered a language, I say it's a perfectly valid example.

DVK
  • 126,886
  • 32
  • 213
  • 327
  • Yes, chaining is *possible* but only if you construct the class that way. What if you don't have control over the class, want to pass it into a method on a different class, or the methods don't return `this`? – mpen Nov 26 '10 at 02:13
  • @Ralph - see the second part for non-OO-instance-returning example – DVK Nov 26 '10 at 02:21
  • Shell is what I had in mind... but it's not a very nice "programming language". I don't know of anyone who writes full blown programs in it? – mpen Nov 26 '10 at 02:30
  • 1
    @Ralph - I have at one point actively maintained and written large chunks of a system consisting of ~100,000-lines of ksh code. I was young and fearless back then (and wrote large and complicated DOS batch scripts as a teen :) ) – DVK Nov 26 '10 at 02:43
  • @DVK: I think that just makes you crazy :) – mpen Nov 26 '10 at 02:56
3

Well, you can do this in JavaScript and its relatives:

function compose()
{
    var funcs = Array.prototype.slice.call(arguments);
    return function(x)
    {
        var i = 0, len = funcs.length;
        while(i < len)
        {
            x = funcs[i].call(null, x);
            ++i;
        }
        return x;
    }
}

function doubleIt(x) { print('Doubling...'); return x * 2; }

function addTwo(x) { print('Adding 2...'); return x + 2; }

function tripleIt(x) { print('Tripling...'); return x * 3; }

var theAnswer = compose(doubleIt, addTwo, tripleIt)( 6 );
print( 'The answer is: ' + theAnswer );
// Prints:
//   Doubling...
//   Adding 2...
//   Tripling...
//   The answer is: 42

As you can see, the functions read left-to-right and neither the object nor the functions need any special implementation. The secret is all in compose.

Zecc
  • 4,220
  • 19
  • 17
  • +1 for proposing a solution that doesn't have to be baked into the class itself. I'm not sure I'd ever use that, but it's interesting :) – mpen Nov 27 '10 at 03:30
2

Haskell. The following three examples are equivalent:

  • i(h(g(f(x)))) (Nested function calls)
  • x & f & g & h & i (Left-to-right chaining as requested)
  • (i . h . g . f)(x) (Function composition, which is more common in Haskell)

http://www.haskell.org/haskellwiki/Function_composition

http://en.wikipedia.org/wiki/Function_composition_(computer_science)

Palle Due
  • 5,929
  • 4
  • 17
  • 32
S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • 3
    The example they give there, `desort = (reverse . sort)`. This actually performs the *sort* first... so you still have to read it backwards. That doesn't make any sense to me? – mpen Nov 26 '10 at 02:23
  • 3
    @Ralph: "That doesn't make any sense to me?". The Haskell folks like it that way. There are probably a real lot of Haskell programmers who like it that way and would call your version backwards. It might be good to reserve judgement. – S.Lott Nov 26 '10 at 02:42
  • @S.Lott: To each his own. I'm sure they have reasons for liking it that way; I'm just stating *my* opinion. Regardless, this question is about "forward composition" or "left-to-right piping" or what have you. – mpen Nov 26 '10 at 02:55
  • This is not what I would call pipelining, but function composition..pipelining is not part of haskellers culture ;). Check this thread: http://stackoverflow.com/questions/1457140/haskell-composition-vs-fs-pipe-forward-operator – elmattic Nov 26 '10 at 02:59
  • 1
    @Raplh: Your opinion isn't really material, here. The Haskell language is what it is. It's widely used. Please try to focus on *learning* something. Your opinion could change if you were to actually *learn* something about Haskell. – S.Lott Nov 26 '10 at 02:59
  • 2
    @S.Lott: I *am* here to learn something, I'm just not here to learn *Haskell* at this point in time. Don't take that personally. And of course my opinion is relevant; I asked the question, which was *not* "what's your favorite programming language, regardless if it meets these conditions?". I appreciate that Haskell is *similar* to what I'm after, but I don't really see why you're trying to force it upon me. – mpen Nov 26 '10 at 03:14
  • 2
    @Ralph: Learning Haskell is not the point. Learning the various approaches and various terminology is the point. Your opinion on Haskell (and left-vs-right) is irrelevant. I'm not forcing anything. I'm encouraging you to actually learn something and not limit your learning based on your opinions. – S.Lott Nov 26 '10 at 13:38
  • 1
    @S.Lott: I teach myself new things every day, but unfortunately, I just can't absorb everything all at once. I simply don't have time to learn Haskell right now. I'd like to learn it one day, but it's kind of lower on my priorities. I've got about 5 languages under my belt so far, next I'm thinking Ruby, F#, or Go. I like to learn what interests me the most, and what I think has a future. Learning various approaches is great, but I'd like to be in charge of what approach I learn next. Terminology, fine, that takes 2 seconds to pick up a new word. However, "function composition" ... – mpen Nov 27 '10 at 03:26
  • ... sounds like combining functions to build a more complicated one. It says nothing about how those functions are combined, or in what order they are combined. Thus, it does not adequately describe what I had in mind. – mpen Nov 27 '10 at 03:27
  • @Ralph: "I simply don't have time to learn Haskell right now." I already agreed with this. Why repeat it? Learning the various approaches and various terminology is the point. "says nothing about ... what order they are combined". Clearly, this cannot be true, or no one could use Haskell. Your impression must, logically, be wrong. Perhaps if you took the time to learn just a little, you might have a clearer idea of what function composition is. – S.Lott Nov 29 '10 at 00:59
  • *Haskell* defines how functions are composed together, but I don't think it's inherent in the definition of "function composition" itself (independently of any programming language). – mpen Nov 29 '10 at 04:46
  • I’m late to the party but Haskell *does* support forward chaining out of the box: `x & f & g & h` is equivalent to `h(g(f(x)))` – Luke Worth May 09 '19 at 08:05
2

What you're describing is essentially the Fluent Interface pattern.

Wikipedia has a good example from a number of languages:

http://en.wikipedia.org/wiki/Fluent_interface

And Martin Fowler has his write up here:

http://www.martinfowler.com/bliki/FluentInterface.html

As DVK points out - any OO language where a method can return an instance of the class it belongs to can provide this functionality.

Michael Shimmins
  • 19,961
  • 7
  • 57
  • 90
  • Again, *can* but only if the class is designed that way. I was looking for a language where this is the norm, not a special case. – mpen Nov 26 '10 at 02:18
  • PS: Fluent Interface sounds like the correct term for this :) Thanks. (Didn't mean for my comment to sound negative) – mpen Nov 26 '10 at 02:30
2

C# extension methods accomplish something very close to your magical language, if a little less concisely:

x.f()
 .g()
 .h()
 .i();

Where the methods are declared thus:

static class Extensions 
{
    static T f<T>(this T x) { return x; }
    static T g<T>(this T x) { return x; }
    ...
}

Linq uses this very extensively.

Serguei
  • 2,910
  • 3
  • 24
  • 34
  • Yes... and I quite enjoy linq for that reason :) Actually, this came up because I noticed that Linq does it this way, but in Python, list comprehensions and such are kind of done the other way around. – mpen Nov 27 '10 at 03:16
1

I am not suggesting you could use Mathematica if you don't do some math usually, but it certainly is flexible enough for supporting Postfix notation. In fact, you may define your own notation, but let's keep with Postfix for simplicity.

You may enter:

Postfix[Sin[x]]

To get

x // Sin  

Which translates to Postfix notation. Or if you have a deeper expression:

MapAll[Postfix, Cos[Sin[x]]]

To get:

(Postfix[x]//Sin)//Cos  

Where you may see Postfix[x] first, as for Mathematica x is an expression to be evaluated later.

Conversely, you may input:

x // Sin // Cos  

To get of course

Cos[Sin[x]]  

Or you can use an idiom very frequently used, use Postfix in Postfix form:

Cos[x] // Postfix

To get

x // Cos

HTH!

BTW: As an answer to Where's with my magical language,? , see this:

(x//Sin 
  // Cos
  // Exp 
  // Myfunct)  

gives

Myfunct[E^Cos[Sin[x]]]  

PS: As an excercise to the readers :) ... How to do this for functions that take n vars?

Dr. belisarius
  • 60,527
  • 15
  • 115
  • 190
1

As has been previously mentioned, Haskell supports function composition, as follows:

(i . h . g . f) x, which is equivalent to: i(h(g(f(x))))

This is the standard order of operations for function composition in mathematics. Some people still consider this to be backward, however. Without getting too much into a debate over which approach is better, I would like to point out that you can easily define the flipped composition operator:

infixr 1 >>>, <<<
(<<<) = (.) -- regular function composition
(>>>) = flip (.) -- flipped function composition

(f >>> g >>> h >>> i) x
    -- or --
(i <<< h <<< g <<< f) x

This is the notation used by the standard library Control.Category. (Although the actual type signature is generalized and works on other things besides functions). If you're still bothered by the parameter being at the end, you can also use a variant of the function application operator:

infixr 0 $
infixl 0 #
f $ x = f x -- regular function application
(%) = flip ($) -- flipped function application

i $ h $ g $ f $ x
    -- or --
x % f % g % h % i

Which is close to the syntax you want. To my knowledge, % is NOT a built-in operator in Haskell, but $ is. I've glossed over the infix bits. If you're curious, thats a technicality that makes the above code parse as:

(((x % f) % g) % h) % i -- intended

and not:

x % (f % (g % (h % i))) -- parse error (which then leads to type error)
Jonathan
  • 2,043
  • 2
  • 13
  • 16
  • If S.Lott had answered like this, I would have been much more appreciative. Now that's cool :) Thank you! And you're right, having `x` on the end still would have bugged me :) – mpen Dec 02 '10 at 21:56