5
$\begingroup$

Maybe this is not even possible:

I want to create a function f that can have two input brackets like:

f[a_][b_:1]:= a*b

and alternatively just one input bracket:

f[a_]:= a

But with overloading the definitions the second definition interferes with the first definition, because the pattern f[a_] is replaced in a expression like:

In:

f[2][3]

Out:

2[3]

with the result of f[2] (in this case)

Of course, I could use just one bracket slot like f[a_,b_:1], instead of f[a_][b_:1], but thats not the point.

So i am asking for an optional bracket slot. Is that possible?

(BTW, I dont know the correct name of the []-Pattern, and called it bracket slot)

$\endgroup$
  • 3
    $\begingroup$ Just curious, why not f[a_] and f[a_, b_], or two different functions? $\endgroup$ – 2012rcampion Feb 27 '15 at 0:26
  • $\begingroup$ Related: (5686494), (544), (9741), (42030) $\endgroup$ – Mr.Wizard Feb 27 '15 at 0:53
  • $\begingroup$ @2012rcampion i know that this is a very special case, but sometimes i want to have both possibilities with the same function. $\endgroup$ – sacratus Feb 27 '15 at 1:23
  • $\begingroup$ @sacratus It actually seems rather natural to me, though in my opinion one must choose between this syntax and Currying as using them concurrently (not for the same function) would be quite confusing. $\endgroup$ – Mr.Wizard Feb 27 '15 at 1:25
6
$\begingroup$

In the Standard Evaluation Sequence the heads of expressions are evaluated first:

  1. If the expression is a raw object (e.g., Integer, String, etc.), leave it unchanged.

  2. Evaluate the head h of the expression.

  3. Evaluate each element of the expression in turn ...

Therefore since f[1] is the head of f[1][2] it will evaluate if it has a definition that matches. This is unavoidable in standard evaluation. To get around this requires Stack trickery that Leonid illustrated here. It works on the principle that f is the head of f[1] itself and is therefore evaluated first of all.

Here is a meta-function to automate his method:

SetAttributes[deepDefine, HoldAll]

deepDefine[s_Symbol, LHS_, RHS_] :=
  s :=
   With[{stack = Stack[_]},
    With[{fcallArgs = Cases[stack, HoldForm[LHS] :> RHS]},
     (First@fcallArgs &) & /; fcallArgs =!= {}
    ]
   ]

We now apply it like this:

ClearAll[f]

deepDefine[f, f[a_][b_: 1], a*b]

f[a_] := a

Test:

f[x]
f[x][y]
f[z][]
x

x y

z
$\endgroup$
  • $\begingroup$ wow, this is impressive! i did not expected, that one found a solution for this. Thanks you very much! $\endgroup$ – sacratus Feb 27 '15 at 1:19
  • $\begingroup$ @sacratus All the credit for this method goes to Leonid; please vote for his answer. I just "put a ribbon on it" with deepDefine. :-) $\endgroup$ – Mr.Wizard Feb 27 '15 at 1:21
  • $\begingroup$ I allready upvoted Leonids answer, but refering to a good existing answer is also honorable :-) $\endgroup$ – sacratus Feb 27 '15 at 4:36
  • 1
    $\begingroup$ @sacratus: just as an advice, I think you really should think about the last sentence in Leonids answer before building "prodution code" that relies on Stack... $\endgroup$ – Albert Retey Feb 27 '15 at 9:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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