8
$\begingroup$

How to specify optional arguments that take functional values made me wonder: Can we come up with a variant of Optional that allows to do the following:

lhs = x_;
g[lhs~HeldOptional~RandomReal[]] := x
DownValues@g

and get

{HoldPattern[g[Optional[x_, RandomReal[]]]] :> x}

Specifically, I want HeldOptional to evaluate the left hand side like all pattern construction constructs, while leaving the right argument untouched.

The following attempt does not work:

HeldOptional~SetAttributes~HoldRest
HeldOptional[x_, y_] := Optional[x, Unevaluated@y]

This gives the DownValue

{HoldPattern[g[x_ : Unevaluated[RandomReal[]]]] :> x}

such that g[] gives Unevaluated[RandomReal[]] instead of a random real.

$\endgroup$
4
  • $\begingroup$ This is also related: mathematica.stackexchange.com/questions/29013/… $\endgroup$
    – masterxilo
    Commented Aug 18, 2016 at 17:13
  • $\begingroup$ I guess one way to start would be to overload x:SetDelayed[___]/;!FreeQ[x,HeldOptional]:=... to automate what QuantumDot suggested. $\endgroup$
    – masterxilo
    Commented Aug 30, 2016 at 21:16
  • 1
    $\begingroup$ HeldOptional = Function[, HoldPattern@Optional[#1, #2], HoldRest]? $\endgroup$
    – jkuczm
    Commented Sep 11, 2016 at 18:40
  • $\begingroup$ @jkuczm HoldPattern, of course! Please post an answer ;) $\endgroup$
    – masterxilo
    Commented Sep 12, 2016 at 21:46

2 Answers 2

5
$\begingroup$

Putting together idea from question to use function with HoldRest attribute, together with idea from QuantumDot's answer to use HoldPattern we get:

ClearAll[HeldOptional]
HeldOptional~SetAttributes~HoldRest
HeldOptional[x_, y_] := HoldPattern@Optional[x, y]

HoldPattern wraps whole Optional pattern, but since function has only HoldRest attribute, its firs argument evaluates before it's passed to held pattern.

Using HeldOptional we get definitions equivalent to requested one:

ClearAll[lhs, g]
lhs = x_;
g[lhs~HeldOptional~RandomReal[]] := x
DownValues@g
(* {HoldPattern[g[HoldPattern[x_ : RandomReal[]]]] :> x} *)

and desired behavior:

g[a]
(* a *)
g[]
(* 0.408798 *)
g[]
(* 0.0652214 *)
g[]
(* 0.587329 *)
$\endgroup$
1
$\begingroup$

This works:

ClearAll[DontEvaluateInOptional];
DontEvaluateInOptional~SetAttributes~HoldAllComplete;
DontEvaluateInOptional /: (h: Except[Optional])[l___, 
   HoldPattern@DontEvaluateInOptional[b___], r___] := h[l, r, b];

HeldOptional~SetAttributes~HoldRest
HeldOptional[x_, y_] := Optional[x, DontEvaluateInOptional@y]

lhs = x_;
g[lhs~HeldOptional~RandomReal[]] := x
DownValues@g

g[3]
g[]
g[]

Out[39]= {HoldPattern[g[x_:DontEvaluateInOptional[RandomReal[]]]]:>x}

Out[40]= 3

Out[41]= 0.0769485

Out[42]= 0.674345

This is a bit superior to the Unevaluated method I suggested first because it is stripped in more cases, but it cannot insert the default value into HoldAllComplete symbols:

ClearAll[f,g];
f~SetAttributes~HoldAllComplete
g[x_~HeldOptional~RandomReal[]] := f[x]
g[3]
g[]

Out[46]= f[3]

Out[47]= f[DontEvaluateInOptional[RandomReal[]]]

$\endgroup$
1
  • $\begingroup$ and for HoldAll symbols, the default is inserted unevaluated which may or may not be what you want $\endgroup$
    – masterxilo
    Commented Aug 30, 2016 at 21:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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