Mathematica Asked on August 9, 2021
I want to refer to the actual option values of a function f
outside of f
, using OptionValue
. Since I would use the same reference in different function f
, g
, etc., each resolving to its own actual option values, I do not want to specify the function name f
in the external OptionValue
call.
OptionValue["opt"]
is not resolved to OptionValue[f, "opt"]
inside f
. Can I circumvent this without explicitly stating OptionValue[f, "opt"]
in the external assoc
? BTW, that wont’ work either, returning the default 1 instead of 2.
ClearAll[f];
Options[f] = {"opt" -> 1};
f[x_, OptionsPattern[]] := {
OptionValue["opt"], (* This is evaluated correctly *)
x["Option"], (* This is not resolved correctly *)
Evaluate[x["Option"]] (* This is not resolved correctly *)
};
assoc = <|"Option" :> OptionValue["opt"]|>
f[assoc, "opt" -> 2]
Output:
{2, OptionValue["opt"], OptionValue["opt"]}
My expected result would be {2, 1, 1}
, though I understand that the special nature of OptionValue
prevents the kernel to resolve OptionValue["opt"]
to OptionValue[f, "opt"]
at the time it is first encountered.
We can (ab)use the automatic expansion of OptionValue
into its three-argument-form, which works even inside rules:
Options[func] = {"opt" -> None};
{func["opt" -> 1], func[]} /. func[OptionsPattern[]] :> OptionValue["opt"]
(* {1, None} *)
Now, for your example: First, we define iExpandOptionValue
that expands OptionValue
into a list of expressions using the trick above.
Attributes[iExpandOptionValue] = {HoldAll};
iExpandOptionValue[OptionValue[head_, opts_, __], vars___] :=
Hold[vars] /. <|args___|> :> <|args|> /. Hold[evars___] :> (
Unevaluated@head[opts] /. HoldPattern@head[OptionsPattern[]] :> {evars}
)
Note the /. <|args___|> :> <|args|>
trick. This makes sure that associations inside vars
are not initialized, since otherwise the replacement doesn't work as expected.
Next, we define ExpandOptionValue
. It is used as the right side of a definition, where the first argument specifies variables to "expand" using the function above, and the second argument is the expression to evaluate.
HoldPattern[lhs_ := ExpandOptionValue[{vars___}, rhs_]] ^:=
Replace[
{Hold[rhs], Quiet@Replace[Hold[vars], var_ :> Pattern[var, _], 1]},
{Hold[rhs2_], Hold[pats___]} :> (
lhs := iExpandOptionValue[OptionValue["dummy"], vars] /. {pats} :> rhs2
)
]
We use a similar trick to above to extract the function on the left side using OptionValue["dummy"]
, which we can then pass to iExpandOptionValue
. After some more replacements, we are finally done. We can now use this on your example:
ClearAll[f];
Options[f] = {"opt" -> 1};
f[x_, OptionsPattern[]] := ExpandOptionValue[{x},
x["Option"]
];
assoc = <|"Option" :> OptionValue["opt"]|>;
f[assoc, "opt" -> 2]
(* 2 *)
To see a bit what's going on, we can look at the definition of f
:
Definition@f
(* f[x$_,OptionsPattern[]]:=iExpandOptionValue[OptionValue[dummy],x$]/. {x_}:>x[Option]
Options[f]={opt->1} *)
Correct answer by Lukas Lang on August 9, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP