1
$\begingroup$

I have the following function to create DownValues for some symbol when desired:

str = "p"; int = 5;

SetAttributes[addDownValuesRuntime, HoldAll];
addDownValuesRuntime[func_Symbol, args__, body_] := With[{arg = Unevaluated[args]},
SetDelayed @@ Hold[func[arg], body]
];

If I make my function definition such that the args are encapsulated by braces i.e. {str_String, int_Integer} I note that the arguments for the defined function f are also encapsulated by { } :

addDownValuesRuntime[f, {str_String, int_Integer}, {str,int}];
??f
(* f[{str_String,int_Integer}]:= {str,int} *)

However, if I make my definition like this (args not encapsulated) then the args are inside Sequence and I cannot :

addDownValuesRuntime[f, str, int, {str,int}];
??f
(* f[Sequence[str,int]]:= {str,int} *)

In this case I cannot use the function.

My question is how to get rid of Sequence such that my final function definition looks like f[str_String,int_Integer]:= body; or f[str,int]:= body

Any help will be very much appreciated

$\endgroup$
  • $\begingroup$ No need to get rid of Sequence since f[Sequence[str,int]]:= {str,int} is equivalent to f[str,int]:= {str,int}. $\endgroup$ – Henrik Schumacher Dec 10 '17 at 7:35
  • $\begingroup$ @HenrikSchumacher I am not able to use f[1,2] after function definition. it is evaluating to itself. $\endgroup$ – Ali Hashmi Dec 10 '17 at 8:20
  • 2
    $\begingroup$ Indeed, that's puzzling since f[Sequence[str_String, int_Integer]] := {str, int} and f[str_String, int_Integer] := {str, int} produce perfectly the same function. SetDelayed has the rather seldom attribute SequenceHold. Must be related to that. Btw.: Why don't you use addDownValuesRuntime[func_Symbol, args__, body_] := SetDelayed[func[args], body];? $\endgroup$ – Henrik Schumacher Dec 10 '17 at 8:36
  • 1
    $\begingroup$ Instead of addDownValuesRuntime[f, a1, a2,..., b]], why not f[a1, a2,...] := b? $\endgroup$ – Michael E2 Dec 10 '17 at 16:41
  • $\begingroup$ @MichaelE2 thanks ! was somehow challenging myself :) $\endgroup$ – Ali Hashmi Dec 10 '17 at 17:12
5
$\begingroup$

What is wrong with

ClearAll[addDownValuesRuntime];
SetAttributes[addDownValuesRuntime, HoldAll];
addDownValuesRuntime[func_Symbol, args__, body_] := (func[args] := body);

?

$\endgroup$
  • $\begingroup$ if you do this with the above code: addDownValuesRuntime[f, {str, int}, {str, int}] then we get a premature evaluation of the arguments of the function. f[{p,5}]:={str,int}. It is not a great deal though since any global definitions will eventually cause the definition to result in the same value. I was deliberately avoiding this solution on purpose. +1 nevertheless $\endgroup$ – Ali Hashmi Dec 10 '17 at 17:08
1
$\begingroup$

I don't know that it is useful to do what you asked for, but in my opinion a simpler method would be:

SetAttributes[addDownValuesRuntime,HoldAll];
addDownValuesRuntime[func_Symbol,args__, body_]:=With[{old=Attributes[func]},
    Internal`WithLocalSettings[
        SetAttributes[func,HoldAll],
        SetDelayed[func[args],body],
        Attributes[func]=old
    ]
]

For your "evaluation" leak example:

str = "p"; int = 5;

addDownValuesRuntime[f, str, int, {str, int}]

DownValues[f]

{HoldPattern[f[str, int]] :> {str, int}}

$\endgroup$
0
$\begingroup$
ClearAll[addDownValuesRuntime, f]

str = "p"; int = 5; (* global values defined to test if our code binds the definition to
function f without evaluating these OwnValues *)

SetAttributes[addDownValuesRuntime, HoldAll];
addDownValuesRuntime[func_Symbol, {args__}, body_] := 
Block[{setdelayed = SetDelayed},
SetAttributes[setdelayed, HoldAll];
Apply[setdelayed,{func[GeneralUtilities`HoldSymbolName /@ Unevaluated[args]] /. 
  GeneralUtilities`HoldSymbolName[x___] :> x, Unevaluated@body}
 ]
];

To test if the code works properly (sanity checks):

addDownValuesRuntime[f, {str, int}, {str, int}];

?f
(* f[str,int]:={str,int} *)  (* as expected the body and arguments did not
evaluate prematurely *)

Furthermore,named patterns seem to work fine as well:

addDownValuesRuntime[f, {str_String, int_Integer}, {str, int}];
(* f[str_String,int_String] := {str,int} *)

calling the functions

f["string", 2]
(* {"string", 2} *)

f[str, int]
(* {"p", 5} *)
$\endgroup$
  • $\begingroup$ actually in the above code we do not need to even define setdelayed. SetDelayed works equally fine ! $\endgroup$ – Ali Hashmi Dec 10 '17 at 17:16
  • 1
    $\begingroup$ Have you tried calling your f with the new definition you added? $\endgroup$ – halirutan Dec 10 '17 at 17:29
  • $\begingroup$ @halirutan seems to be working fine. let me add it $\endgroup$ – Ali Hashmi Dec 10 '17 at 20:31

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.