15

Often I want a version of @ that is left-associative (might not be using that term correctly).

What I mean is I'd like some operator l@ such that:

a l@ b l@ c === a[b][c]

Standard @ gives us:

a @ b @ c === a[b[c]]

Is there such an operator I've overlooked? (I don't want to use brackets on brackets on brackets)

b3m2a1
  • 46,870
  • 3
  • 92
  • 239
  • 2
    Related: https://mathematica.stackexchange.com/q/11908/403 – M.R. Jan 23 '19 at 06:54
  • 1
    Also: https://mathematica.stackexchange.com/q/6355/403 – M.R. Jan 23 '19 at 06:55
  • 1
    Interesting question, can it be that the documentation is wrong for Infix? According to documentation something like Infix[ f[a,b,c], "~", 490, Left ] is supposed to word but does not. The same syntax should also work for Prefix. – gwr Jan 23 '19 at 10:19
  • 1
    Being pedantic, the title of the question isn't strictly correct: Apply is @@, not @. The operators @ and // are both called "function application" in the Docs. So more correct title would be "Function application with left-associative grouping". – Alexey Popkov Feb 11 '19 at 11:02

2 Answers2

14

I am not aware of a built-in operator that will call a function with individual sub-value arguments (i.e. curried arguments).

The function Curry has a promising-sounding name, but it lifts a function that takes uncurried arguments into one that takes curried arguments -- sort of the opposite of what we want here.

We could define our own by pressing one of the operators without built-in meanings into service. Let's use CirclePlus () in one of the following ways:

CirclePlus[f_, r___] := Fold[Construct, f, {r}]

or prior to version 11.3:

CirclePlus[f_, r___] := Fold[#[#2]&, f, {r}]

or using the now undocumented function HeadCompose:

CirclePlus = HeadCompose;

With any of these, we can then write:

f⊕a

(* f[a] *)

f⊕a⊕b

(* f[a][b] *)

f⊕a⊕b⊕c

(* f[a][b][c] *)

f⊕a⊕b⊕c⊕d

(* f[a][b][c][d] *)
WReach
  • 68,832
  • 4
  • 164
  • 269
  • As I noted in a comment to Carl Woll the issue is that I can't trust these operator forms to not have rules attached to them by someone else. I don't like to play with "System`" level symbols since I can't scope them without potentially breaking someone else's code. What I had to do, inefficient though it is, was to simply attach a DownValue to my primary object that took a pattern like a["method"[]@["property"]] and rewrite it as a["method[]]@"property". As long as I use strings for method and property names there's no danger with premature evaluation here. – b3m2a1 Sep 13 '19 at 23:01
  • 1
    @b3m2a1 I'm inclined to agree with you about overloading the operator forms. It is a powerful tool for project work... but use in library code is downright dangerous. – WReach Sep 13 '19 at 23:29
12

Another alternative is to use a built-in operator form that has left-associative grouping. A couple examples:

CircleMinus[a_, b_] := a[b]
a ⊖ b ⊖ c

a[b][c]

LeftTee[a_, b_] := a[b]
a ⊣ b ⊣ c

a[b][c]

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
  • Thank you! I have been looking for a left-associative operator for a long time! I suppose that in order to fully emulate parsing behavior of @, it would be a good idea to add HoldAllComplete as well. Compare with and without HoldAllComplete: a[b] = HoldComplete; c = 1; a\[CircleMinus]b\[CircleMinus]c – Anton.Sakovich Jan 24 '19 at 08:13
  • I'm always uncomfortable using these built-in operators because I don't want to take one out of commission for other people... On the other hand I can't just use my own symbol and attach a MakeBoxes rule to it because this needs to work inside a package -_- It's just too dangerous, though, to use one of these "System`" level ones since there's no way to scope its effect. – b3m2a1 Sep 13 '19 at 23:00
  • 1
    @b3m2a1 Would having an input alias work for you? Or does it have to be InputForm only because it's in a package? – Carl Woll Sep 17 '19 at 00:22
  • It would be used in a package unfortunately. Realistically no one else will ever use it, probably, but I’d like to adhere to good development practices despite that. – b3m2a1 Sep 17 '19 at 00:24