Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

The question is simple, but I will elaborate on the background as well for those interested in the idea:

How to define a new operator with specified precedence value?


Background

Mathematica was design to facilitate functional programming. I definitely find it easy to write code continuously: the output of a function becomes immediately the input of the next function. One thing I really miss though is a low-precedence prefix operator that applies to all things following it (up to e.g. CompoundExpression (;)). Consider the following example:

Log@N@Accumulate@# & /@ Partition[Range@300, 100] // Flatten // ListPlot

It partitions a dataset to multiple subparts, threads functions to each subpart, and then plots the joined datasets. I write such code a lot, as I find it easy that it can be written from the inside to the outside, from argument to head (right to left). The problem is that the extension of the above one might come up with intuitively does not behave like that:

ListPlot@Flatten@ Log@N@Accumulate@# & /@ Partition[Range@300, 100]

Operator precedences cause ListPlot@Flatten do be applied to each subpart of the partitioned list instead of the list as a whole. Now since I successively build up my calculations from the argument to the wrapping functions, I want to use a prefix operator. My concerns are:

  • One can use matchfix forms like f@(...) or f[...] to wrap around the Map, though it requires the matching of parentheses, which can be a PITA when multiple such functions are applied with prefix notation.
  • Using postfix // both breaks my cognitive process of writing from right-to-left, and (more importantly) breaks the principle of head-precedes-argument, which is very emphasized in Mathematica (and in $\lambda$-calculus).
  • The operator must be a free symbol. Modifying the built in @ operator should be avoided!
  • Also it must be simple enough to be used effectively. Postfix apply // is 2 keystrokes, while for example $\oplus$ requires 4 (escc+esc), making it worse than hitting end//.

So, how to define a new operator, e.g. \\ that has low precedence (perhaps 70) so that this:

ListPlot \\ Flatten \\ Log@N@Accumulate@# & /@ Partition[Range@300, 100]

equals this:

ListPlot[Flatten[Log@N@Accumulate@# & /@ Partition[Range@300, 100]]]

Frankly, I just started to wonder why this operator is not present at all in Mathematica, though WRI always emphasizes functional programming as a native style of the language.


I know I can apply Log or N to the partitioned list as a whole. I only used them here for demonstrating my case.

share|improve this question
    
Have you studied the Notation package? I have no experience with it, but it seems to be the way to go. Another thing: converting a string to an expression starts by first parsing it. I don't think the parser is customizable, so I don't think it's possible to do this so that it'd work with the command line interface. What we might be able to do is customize how to get from boxes (not a string) to expressions and vice versa. If it is at all possible to alter the precedence (I don't know if it is or not!), the information about the precedence should be somehow embedded in the (contd.) –  Szabolcs Jun 2 '12 at 10:23
    
boxes. This means that it will not be possible to enter our new operator as a simple string because we'll need to somehow enter this special box information. We might be able to define a keyboard shortcut that enters everything correctly, or maybe use the auto-replacement feature (that replaces e.g. "Mathematica" by "Mathematica") to always replace `\` by the correct box structure. Just some thoughts ... –  Szabolcs Jun 2 '12 at 10:25
    
@Szabolcs: I vaguely remember encountering some file in the Mathematica folder that contains all the precedences. And also there is PrecedenceForm, though that is not really helpful here. As always, I'd rather avoid using the Notation package, as it involves a lot of overhead for such a small functionality. I really hope someone could post a simple solution for such an obvious problem, though in the meantime I try to figure out something from the Notation pkg. –  István Zachar Jun 2 '12 at 10:29
1  
This came up here on MG: groups.google.com/d/topic/comp.soft-sys.math.mathematica/… I seems to recall seeing it somewhere else as well, but I can't find it. While theoretically it's an interesting problem (and +1), there's always the concern that a personal custom notation that is not tied to a special custom function (but a built-in operation such as function application) would be a severe hindrance when sharing code. –  Szabolcs Jun 2 '12 at 10:30
1  
Yes, I am aware of this aspect (non-distributability of custom notation). As a matter of fact, I really suppressed this question since long but yesterday I felt an urge of rage-posting because I got fed up jumping back and forth of the start and end of an otherwise nicely building piece of code. Also, I hope that such changes can be done in the form of oneliners, so it would be easy to distribute the operator definition with any work intended for sharing. Lastly (a dream): WRI might decide on including it in Mathematica later if they see this is viable and useful. –  István Zachar Jun 2 '12 at 10:39
add comment

1 Answer 1

up vote 21 down vote accepted

As explained by Michael Pilat you cannot create your own compound operators with custom precedence. (You could conceivably write your own parser as Leonid has worked on, or attempt to coerce the Box form with CellEvaluationFunction.)

You can however use an existing operator with the desired precedence. Looking at the table Colon appears to be a good choice. The operator is entered with Esc:Esc. Example:

SetAttributes[Colon, HoldAll]
Colon[f__, x_] := Composition[f][Unevaluated@x]

ListPlot \[Colon] Flatten \[Colon] Log@N@Accumulate@# & /@ Partition[Range@300, 100]

Which appears as, and produces:

Mathematica graphics

Mathematica graphics

Since raw colon is already used for Pattern this may be confusing. However, if you are willing to edit your UnicodeFontMapping.tr file you can assign any symbol you like. Here I mapped \[Colon] to Klingon A:

Mathematica graphics

This was done by changing the line starting with 0x2236 in UnicodeFontMapping.tr.

share|improve this answer
    
Very helpful answers, both yours and Michael's, thanks! –  István Zachar Jun 2 '12 at 12:37
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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