14
$\begingroup$

I can't find the link anymore but there was a talk at a Wolfram conference (referencing v7 I think) where the authors highlight that stringing together functions like this:

Range[100] // Partition[#,10]& // Grid[#, Spacings->{1,1}]&

allows you to add arguments to the post-fix function, string together more than one function and reads nicely left-to-right. I have to admit, I find this a nice way to string together functions and wonder why it's not more prevalent. I know there are some subtle precedence issues with post-fix notation so maybe it's just simply more trouble free in the long term if you get used to nesting your functions.

My question: is this just a style issue or is there some valid reason for avoiding this habit early?

$\endgroup$
  • 3
    $\begingroup$ I personally prefer this style and have found no issues with it directly but rather with formatting in the frondend. I like putting each //someFunction on a separate line which is only possible in e.g. Module since otherwise each line gets treated as a separate expression to be evaluated. $\endgroup$ – Sascha May 29 '17 at 7:04
  • 5
    $\begingroup$ @Sascha use Mr.W's way of parenthesizing, as in (expr // someFunc1 // someFunc2 ...), then no module is needed $\endgroup$ – LLlAMnYP May 29 '17 at 7:23
  • $\begingroup$ @LLIAMnYP that is a neat trick, thanks a lot! $\endgroup$ – Sascha May 29 '17 at 7:43
  • 1
    $\begingroup$ Related: mathematica.stackexchange.com/q/139344/26956 mathematica.stackexchange.com/q/110067/26956 Don't think this is opinion-based (at worst, the question can be interpreted as "is this opinion-based or objective). Very useful info on precedence and unexpected effects of composition in the accepted answer. Voting leave open. $\endgroup$ – LLlAMnYP Jun 2 '17 at 10:18
9
$\begingroup$

I use this style sometimes, and I see not issues with it.

You mention precedence. A nice thing about // is that it has very low precedence, even lower than &. Thus it is not necessary to parenthesize the functions.

You can use

f @ (#&) @ arg

with the parentheses, or you can use

 arg // #& // f

without them.

One annoying thing about chaining with // is the auto-indentation done by the front end:

Mathematica graphics

I do not like this. Using RightComposition can alleviate the issue:

Mathematica graphics

This is what this looks like in practice in an example in the IGraph/M documentation:

Mathematica graphics

One thing to watch out for with Composition and RightComposition is that they effectively negate any Hold* attributes of the composed functions:

1 + 1 // Hold // f
(* f[Hold[1 + 1]] *)

1 + 1 // Hold /* f
(* f[Hold[2]] *)
$\endgroup$
5
$\begingroup$

As you said, there could be some precedence issues. You can use Defer to check if there is any precedence issues. (I tried to use PrecedenceForm to check precedence, however there is an error message found by Karsten 7. So I used Defer instead.

Defer[Range[10] // Partition[#, 10] & // Grid[#, Spacings -> {1, 1}] &]

(*(Grid[#1, Spacings -> {1, 1}] &)[(Partition[#1, 10] &)[Range[10]]]*)

Or you can use ReverseComposition to avoid precedence issues.

In:

ReverseComposition[fs__] := Composition[Sequence @@ Reverse@{fs}]

partition[xs_] := Partition[xs, 10]
grid[xss_] := Grid[xss, Spacings -> {1, 1}]
f = ReverseComposition[Range, partition, grid]
f@100

Out:

grid@*partition@*Range

Mathematica graphics

$\endgroup$
  • 4
    $\begingroup$ Have you heard of RightComposition? ;-) $\endgroup$ – LLlAMnYP May 29 '17 at 7:24
  • $\begingroup$ @LLlAMnYP I forgot it and I reinvented the wheel... :( $\endgroup$ – UnchartedWorks May 29 '17 at 7:26
  • $\begingroup$ @Karsten7. It isn't always like this. if you use //, sometimes you might encounter precedence issues. $\endgroup$ – UnchartedWorks May 29 '17 at 7:55
  • $\begingroup$ @Karsten7. I got it. Thanks! $\endgroup$ – UnchartedWorks May 29 '17 at 8:13
  • 1
    $\begingroup$ The best input I could come up with, that produces an output similar to the one you originally got without using invalid input is: Range[100] // Partition[#, 10] & // Grid[#, Spacings -> {1, 1}] & // Inactivate // Activate[#, Function] & $\endgroup$ – Karsten 7. May 29 '17 at 8:25
5
$\begingroup$

Precedence is only an issue if your input contains a lot of different operators and you aren't aware of their precedence. For example, something like

expr1 /* expr2 // expr4~expr5~expr6 @ expr7

Here you can find a list with the most common operators listed in order of decreasing precedence. This answer contains information on how to find the precedence of an operator and a link to the A New Mathematica Programming Style presentation from the 2007 Wolfram Technology Conference.

The main reason not to use postfix and prefix notation excessively in the final code is performance. Especially when using a lot of computational cheap pure functions, such as in your input example, the introduced overhead is significant:

Table[
  {(Range[100] // Partition[#, 10] & // 
        Grid[#, Spacings -> {1, 1}] & // AbsoluteTiming // 
      First)/(Grid[Partition[Range[100], 10], Spacings -> {1, 1}] // 
       AbsoluteTiming // First),
   (Grid[#, Spacings -> {1, 1}] &@Partition[#, 10] &@Range[100] // 
       AbsoluteTiming // 
      First)/(Grid[Partition[Range[100], 10], Spacings -> {1, 1}] // 
       AbsoluteTiming // First)}
  , 200] // Mean

{1.23117, 1.23615}


I mainly use postfix notation for the output styling part of my code. The personal preferences for different input forms is probably due to one's flow of thinking and programming. f[x] is closed to the mathematical notation $ f(x) $ and f @ x is like saying " f of x" or "f applied to x". Both these notations are very similar in their logic, as they start with the output one wants to get or the thing one wants to do, whereas x // f // g is more inline with a step-by-step approach of "first take/make x, than apply f to it, and finally do g".

$\endgroup$
  • $\begingroup$ It's informative. I have downloaded the Regarding f@arg, it says that it requires some knowledge of the 1000-level Precedence table. It's hard. $\endgroup$ – UnchartedWorks May 29 '17 at 11:24

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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