Skip to main content
replaced http://mathematica.stackexchange.com/ with https://mathematica.stackexchange.com/
Source Link

To make our environment easier to use, in function definitions, let's add some macro tricks stolen from Leonidstolen from Leonid:

To make our environment easier to use, in function definitions, let's add some macro tricks stolen from Leonid:

To make our environment easier to use, in function definitions, let's add some macro tricks stolen from Leonid:

Enhance code formatting, fix some typos.
Source Link
jkuczm
  • 15.2k
  • 2
  • 55
  • 89
ClearAll[symbolToName, deleteOptionDuplicates] symbolToName[sym_Symbol] := SymbolName[sym] symbolToName[arg_] := arg deleteOptionDuplicates[opts:OptionsPattern[]] :=  GatherBy[Flatten[{opts}], symbolToName@First[#]Composition[symbolToName, &][[AllFirst]][[All, 1]] 

Now we can define an environment, providing special option-filtering function:

I guess that extraction of OptionsPattern from lhs could be more general.

Now we can define functions like this:

WithoutIf there are duplicates, first option is used regardless of whether it's name is a symbol or a string:

Usually I don't need to store or return filtered options, I just want to pass them to appropriate function. In In such cases other environment, that setts default option values for some functions, can be useful:

ClearAll[withDefaultOptions] withDefaultOptions[base_Symbol, targets:{__Symbol}, opts___]:= Function[body, With[{allOptions=deleteOptionDuplicates[opts, Options[base]]}, Internal`InheritedBlock[targets, Scan[SetOptions[#Scan[ SetOptions[#, FilterRules[allOptions, Options[#]]]&,   targets]; targets ]; body ] ], HoldFirst ] withDefaultOptions /: Verbatim[SetDelayed][lhs_Verbatim[SetDelayed][ lhs_,  rhs:HoldPattern[withDefaultOptions[_, _,___][_]]] ___][_]]  ] := Block[{With}, Attributes[With]={HoldAll}; lhs := Evaluate[rhs] ] withDefaultOptions /: Verbatim[SetDelayed][h_[pre___Verbatim[SetDelayed][ h_[pre___, optsPatt_OptionsPattern, post___],   HoldPattern[withDefaultOptions[body_]]] HoldPattern[withDefaultOptions[body_]] ] := h[pre, opts:optsPatt,post] :=   withDefaultOptions[h withDefaultOptions[ h,  Cases[Flatten[{First[optsPatt]}], Except[h, _Symbol]],   opts][body] opts  ][body] withDefaultOptions /: Verbatim[SetDelayed][ h_[pre___h_[ pre___,  namedOptsPatt:Verbatim[Pattern][optsName_, optsPatt_OptionsPattern],   post___] post___ ], HoldPattern[withDefaultOptions[body_]] ] := h[pre, namedOptsPatt, post] :=   withDefaultOptions[h withDefaultOptions[ h,  Cases[Flatten[{First[optsPatt]}], Except[h,_Symbol]],   optsName][body] optsName ][body] 

Let's start with a dummy function, to which we'll pass options:

Now a function thethat can accept and pass options to f. It has it'sits own options and some overridden f options, with different defaults.

ClearAll[g]; Options[g] = {"optA" -> "valGA", "optC" -> "valGC"}; g[OptionsPattern[{g, f}]] :=  withDefaultOptions@{OptionValue[{"optA", "optC"}], f[]} 

Notice that we don't have to pass anything to f, in body of g. Proper default options for f are set automatically, by withDefaultOptions, based on what'swhat is matched by OptionsPattern and what is inside OptionsPattern.

If option for f is neither given explicitly, nor set as default on g, then default of f is used.

ClearAll[symbolToName, deleteOptionDuplicates] symbolToName[sym_Symbol] := SymbolName[sym] symbolToName[arg_] := arg deleteOptionDuplicates[opts:OptionsPattern[]] := GatherBy[Flatten[{opts}], symbolToName@First[#] &][[All, 1]] 

Now we can define an environment providing special option-filtering function:

Now we can define functions like this:

Without duplicates:

Usually I don't need to store or return filtered options, I just want to pass them to appropriate function. In such cases other environment can be useful:

ClearAll[withDefaultOptions] withDefaultOptions[base_Symbol, targets:{__Symbol}, opts___]:= Function[body, With[{allOptions=deleteOptionDuplicates[opts, Options[base]]}, Internal`InheritedBlock[targets, Scan[SetOptions[#, FilterRules[allOptions, Options[#]]]&, targets]; body ] ], HoldFirst ] withDefaultOptions /: Verbatim[SetDelayed][lhs_, rhs:HoldPattern[withDefaultOptions[_,_,___][_]]] := Block[{With}, Attributes[With]={HoldAll}; lhs := Evaluate[rhs] ] withDefaultOptions /: Verbatim[SetDelayed][h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withDefaultOptions[body_]]] := h[pre, opts:optsPatt,post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h, _Symbol]], opts][body] withDefaultOptions /: Verbatim[SetDelayed][ h_[pre___, namedOptsPatt:Verbatim[Pattern][optsName_, optsPatt_OptionsPattern], post___], HoldPattern[withDefaultOptions[body_]] ] := h[pre, namedOptsPatt, post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h,_Symbol]], optsName][body] 

Let's start with a dummy function to which we'll pass options:

Now a function the can accept and pass options to f. It has it's own options and some overridden f options with different defaults.

ClearAll[g]; Options[g] = {"optA" -> "valGA", "optC" -> "valGC"}; g[OptionsPattern[{g, f}]] := withDefaultOptions@{OptionValue[{"optA", "optC"}], f[]} 

Notice that we don't have to pass anything to f in body of g. Proper default options for f are set automatically by withDefaultOptions based on what's is matched and what is inside OptionsPattern.

If option for f is neither given explicitly nor set as default on g then default of f is used.

ClearAll[symbolToName, deleteOptionDuplicates] symbolToName[sym_Symbol] := SymbolName[sym] symbolToName[arg_] := arg deleteOptionDuplicates[opts:OptionsPattern[]] :=  GatherBy[Flatten[{opts}], Composition[symbolToName, First]][[All, 1]] 

Now we can define an environment, providing special option-filtering function:

I guess that extraction of OptionsPattern from lhs could be more general.

Now we can define functions like this:

If there are duplicates, first option is used regardless of whether it's name is a symbol or a string:

Usually I don't need to store or return filtered options, I just want to pass them to appropriate function. In such cases other environment, that setts default option values for some functions, can be useful:

ClearAll[withDefaultOptions] withDefaultOptions[base_Symbol, targets:{__Symbol}, opts___]:= Function[body, With[{allOptions=deleteOptionDuplicates[opts, Options[base]]}, Internal`InheritedBlock[targets, Scan[ SetOptions[#, FilterRules[allOptions, Options[#]]]&,    targets ]; body ] ], HoldFirst ] withDefaultOptions /: Verbatim[SetDelayed][ lhs_,  rhs:HoldPattern[withDefaultOptions[_, _, ___][_]]  ] := Block[{With}, Attributes[With]={HoldAll}; lhs := Evaluate[rhs] ] withDefaultOptions /: Verbatim[SetDelayed][ h_[pre___, optsPatt_OptionsPattern, post___],    HoldPattern[withDefaultOptions[body_]] ] := h[pre, opts:optsPatt,post] :=    withDefaultOptions[ h,  Cases[Flatten[{First[optsPatt]}], Except[h, _Symbol]],    opts  ][body] withDefaultOptions /: Verbatim[SetDelayed][ h_[ pre___,  namedOptsPatt:Verbatim[Pattern][optsName_, optsPatt_OptionsPattern],    post___ ], HoldPattern[withDefaultOptions[body_]] ] := h[pre, namedOptsPatt, post] :=    withDefaultOptions[ h,  Cases[Flatten[{First[optsPatt]}], Except[h,_Symbol]],    optsName ][body] 

Let's start with a dummy function, to which we'll pass options:

Now a function that can accept and pass options to f. It has its own options and some overridden f options, with different defaults.

ClearAll[g]; Options[g] = {"optA" -> "valGA", "optC" -> "valGC"}; g[OptionsPattern[{g, f}]] :=  withDefaultOptions@{OptionValue[{"optA", "optC"}], f[]} 

Notice that we don't have to pass anything to f, in body of g. Proper default options for f are set automatically, by withDefaultOptions, based on what is matched by OptionsPattern and what is inside OptionsPattern.

If option for f is neither given explicitly, nor set as default on g, then default of f is used.

Add `deleteOptionDuplicates` function and `withDefaultOptions` environment.
Source Link
jkuczm
  • 15.2k
  • 2
  • 55
  • 89

WeLet's start with slightly modified version of mergeRules, that takes into account fact that options can define an environment providing special option-filtering functionhave symbolic or string names and name -> val is treated the same as "name" -> val:

ClearAll[withOptionsClearAll[symbolToName, getOptions]deleteOptionDuplicates] withOptions[base_Symbol, opts___] symbolToName[sym_Symbol] :=  Function[body, With[ {SymbolName[sym]  allOptionssymbolToName[arg_] := DeleteDuplicates[arg  Replace[  deleteOptionDuplicates[opts:OptionsPattern[]] := Flatten[GatherBy[Flatten[{opts, Options[base]}],  h_[sym_Symbol, val_] :> h[SymbolName[sym],symbolToName@First[#] val]&][[All,  {1}1]]  ]

Now we can define an environment providing special option-filtering function:

ClearAll[withOptions, getOptions]  First[#1] ===withOptions[base_Symbol, First[#2]opts___] &:=   ]Function[body,   With[{allOptions = deleteOptionDuplicates[opts, Options[base]]}, Block[{getOptions = FilterRules[allOptions, Options[#]] &}, body ] ], HoldFirst ] 
withOptions /: Verbatim[SetDelayed][lhs_, rhs : HoldPattern[withOptions[__][_]]] := Block[{With}, Attributes[With] = {HoldAll}; lhs := Evaluate[rhs] ] withOptions /: Verbatim[SetDelayed][ h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withOptions[body_]] ] := h[pre, opts : optsPatt, post] := withOptions[h, opts][body] withOptions /: Verbatim[SetDelayed][ h_[ pre___, namedOptsPatt:Verbatim[Pattern][ optsName_Verbatim[Pattern][optsName_,  optsPatt_OptionsPattern ]_OptionsPattern], post___ ], HoldPattern[withOptions[body_]] ] := h[pre, namedOptsPatt, post] := withOptions[h, optsName][body] 
{TooltipDelay->20} 1 

Usually I don't need to store or return filtered options, I just want to pass them to appropriate function. In such cases other environment can be useful:

ClearAll[withDefaultOptions] withDefaultOptions[base_Symbol, targets:{__Symbol}, opts___]:= Function[body, With[{allOptions=deleteOptionDuplicates[opts, Options[base]]}, Internal`InheritedBlock[targets, Scan[SetOptions[#, FilterRules[allOptions, Options[#]]]&, targets]; body ] ], HoldFirst ] withDefaultOptions /: Verbatim[SetDelayed][lhs_, rhs:HoldPattern[withDefaultOptions[_,_,___][_]]] := Block[{With}, Attributes[With]={HoldAll}; lhs := Evaluate[rhs] ] withDefaultOptions /: Verbatim[SetDelayed][h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withDefaultOptions[body_]]] := h[pre, opts:optsPatt,post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h, _Symbol]], opts][body] withDefaultOptions /: Verbatim[SetDelayed][ h_[pre___, namedOptsPatt:Verbatim[Pattern][optsName_, optsPatt_OptionsPattern], post___], HoldPattern[withDefaultOptions[body_]] ] := h[pre, namedOptsPatt, post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h,_Symbol]], optsName][body] 

Let's start with a dummy function to which we'll pass options:

ClearAll[f]; Options[f] = {"optA" -> "valFA", "optB" -> "valFB"}; f[OptionsPattern[]] := OptionValue[{"optA", "optB"}] 

Now a function the can accept and pass options to f. It has it's own options and some overridden f options with different defaults.

ClearAll[g]; Options[g] = {"optA" -> "valGA", "optC" -> "valGC"}; g[OptionsPattern[{g, f}]] := withDefaultOptions@{OptionValue[{"optA", "optC"}], f[]} 

Notice that we don't have to pass anything to f in body of g. Proper default options for f are set automatically by withDefaultOptions based on what's is matched and what is inside OptionsPattern.

If option for f is neither given explicitly nor set as default on g then default of f is used.

g[] (* {{"valGA", "valGC"}, {"valGA", "valFB"}} *)  g["optA" -> 1] (* {{1, "valGC"}, {1, "valFB"}} *) g["optB" -> 1] (* {{"valGA", "valGC"}, {"valGA", 1}} *) g["optC" -> 1] (* {{"valGA", 1}, {"valGA", "valFB"}} *) 

We can define an environment providing special option-filtering function:

ClearAll[withOptions, getOptions] withOptions[base_Symbol, opts___] :=  Function[body, With[ {  allOptions = DeleteDuplicates[  Replace[   Flatten[{opts, Options[base]}],  h_[sym_Symbol, val_] :> h[SymbolName[sym], val],  {1}  ],  First[#1] === First[#2] &   ]   }, Block[{getOptions = FilterRules[allOptions, Options[#]] &}, body ] ], HoldFirst ] 
withOptions /: Verbatim[SetDelayed][lhs_, rhs : HoldPattern[withOptions[__][_]]] := Block[{With}, Attributes[With] = {HoldAll}; lhs := Evaluate[rhs] ] withOptions /: Verbatim[SetDelayed][ h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withOptions[body_]] ] := h[pre, opts : optsPatt, post] := withOptions[h, opts][body] withOptions /: Verbatim[SetDelayed][ h_[ pre___, namedOptsPatt:Verbatim[Pattern][ optsName_,  optsPatt_OptionsPattern ], post___ ], HoldPattern[withOptions[body_]] ] := h[pre, namedOptsPatt, post] := withOptions[h, optsName][body] 
{TooltipDelay->20} 1 

Let's start with slightly modified version of mergeRules, that takes into account fact that options can have symbolic or string names and name -> val is treated the same as "name" -> val:

ClearAll[symbolToName, deleteOptionDuplicates]  symbolToName[sym_Symbol] := SymbolName[sym] symbolToName[arg_] := arg deleteOptionDuplicates[opts:OptionsPattern[]] := GatherBy[Flatten[{opts}], symbolToName@First[#] &][[All, 1]] 

Now we can define an environment providing special option-filtering function:

ClearAll[withOptions, getOptions] withOptions[base_Symbol, opts___] := Function[body, With[{allOptions = deleteOptionDuplicates[opts, Options[base]]}, Block[{getOptions = FilterRules[allOptions, Options[#]] &}, body ] ], HoldFirst ] 
withOptions /: Verbatim[SetDelayed][lhs_, rhs : HoldPattern[withOptions[__][_]]] := Block[{With}, Attributes[With] = {HoldAll}; lhs := Evaluate[rhs] ] withOptions /: Verbatim[SetDelayed][ h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withOptions[body_]] ] := h[pre, opts : optsPatt, post] := withOptions[h, opts][body] withOptions /: Verbatim[SetDelayed][ h_[ pre___, namedOptsPatt:Verbatim[Pattern][optsName_, _OptionsPattern], post___ ], HoldPattern[withOptions[body_]] ] := h[pre, namedOptsPatt, post] := withOptions[h, optsName][body] 
{TooltipDelay->20} 1 

Usually I don't need to store or return filtered options, I just want to pass them to appropriate function. In such cases other environment can be useful:

ClearAll[withDefaultOptions] withDefaultOptions[base_Symbol, targets:{__Symbol}, opts___]:= Function[body, With[{allOptions=deleteOptionDuplicates[opts, Options[base]]}, Internal`InheritedBlock[targets, Scan[SetOptions[#, FilterRules[allOptions, Options[#]]]&, targets]; body ] ], HoldFirst ] withDefaultOptions /: Verbatim[SetDelayed][lhs_, rhs:HoldPattern[withDefaultOptions[_,_,___][_]]] := Block[{With}, Attributes[With]={HoldAll}; lhs := Evaluate[rhs] ] withDefaultOptions /: Verbatim[SetDelayed][h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withDefaultOptions[body_]]] := h[pre, opts:optsPatt,post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h, _Symbol]], opts][body] withDefaultOptions /: Verbatim[SetDelayed][ h_[pre___, namedOptsPatt:Verbatim[Pattern][optsName_, optsPatt_OptionsPattern], post___], HoldPattern[withDefaultOptions[body_]] ] := h[pre, namedOptsPatt, post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h,_Symbol]], optsName][body] 

Let's start with a dummy function to which we'll pass options:

ClearAll[f]; Options[f] = {"optA" -> "valFA", "optB" -> "valFB"}; f[OptionsPattern[]] := OptionValue[{"optA", "optB"}] 

Now a function the can accept and pass options to f. It has it's own options and some overridden f options with different defaults.

ClearAll[g]; Options[g] = {"optA" -> "valGA", "optC" -> "valGC"}; g[OptionsPattern[{g, f}]] := withDefaultOptions@{OptionValue[{"optA", "optC"}], f[]} 

Notice that we don't have to pass anything to f in body of g. Proper default options for f are set automatically by withDefaultOptions based on what's is matched and what is inside OptionsPattern.

If option for f is neither given explicitly nor set as default on g then default of f is used.

g[] (* {{"valGA", "valGC"}, {"valGA", "valFB"}} *)  g["optA" -> 1] (* {{1, "valGC"}, {1, "valFB"}} *) g["optB" -> 1] (* {{"valGA", "valGC"}, {"valGA", 1}} *) g["optC" -> 1] (* {{"valGA", 1}, {"valGA", "valFB"}} *) 
Source Link
jkuczm
  • 15.2k
  • 2
  • 55
  • 89
Loading