Skip to main content

syntax - Prefix operator with low precedence



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 to 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.



Answer



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.





* Rojo demonstrated that one can create two-dimensional compound operators, meaning use of SubscriptBox, SuperscriptBox, OverscriptBox, etc. See:



Comments

Popular posts from this blog

mathematical optimization - Minimizing using indices, error: Part::pkspec1: The expression cannot be used as a part specification

I want to use Minimize where the variables to minimize are indices pointing into an array. Here a MWE that hopefully shows what my problem is. vars = u@# & /@ Range[3]; cons = Flatten@ { Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; Minimize[{Total@((vec1[[#]] - vec2[[u[#]]])^2 & /@ Range[1, 3]), cons}, vars, Integers] The error I get: Part::pkspec1: The expression u[1] cannot be used as a part specification. >> Answer Ok, it seems that one can get around Mathematica trying to evaluate vec2[[u[1]]] too early by using the function Indexed[vec2,u[1]] . The working MWE would then look like the following: vars = u@# & /@ Range[3]; cons = Flatten@{ Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; NMinimize[ {Total@((vec1[[#]] - Indexed[vec2, u[#]])^2 & /@ R...

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

What is and isn't a valid variable specification for Manipulate?

I have an expression whose terms have arguments (representing subscripts), like this: myExpr = A[0] + V[1,T] I would like to put it inside a Manipulate to see its value as I move around the parameters. (The goal is eventually to plot it wrt one of the variables inside.) However, Mathematica complains when I set V[1,T] as a manipulated variable: Manipulate[Evaluate[myExpr], {A[0], 0, 1}, {V[1, T], 0, 1}] (*Manipulate::vsform: Manipulate argument {V[1,T],0,1} does not have the correct form for a variable specification. >> *) As a workaround, if I get rid of the symbol T inside the argument, it works fine: Manipulate[ Evaluate[myExpr /. T -> 15], {A[0], 0, 1}, {V[1, 15], 0, 1}] Why this behavior? Can anyone point me to the documentation that says what counts as a valid variable? And is there a way to get Manpiulate to accept an expression with a symbolic argument as a variable? Investigations I've done so far: I tried using variableQ from this answer , but it says V[1...