# How to get rid of Sequence in the arguments of a DownValue generated at runtime

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

str = "p"; int = 5;

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

• No need to get rid of Sequence since f[Sequence[str,int]]:= {str,int} is equivalent to f[str,int]:= {str,int}. – Henrik Schumacher Dec 10 '17 at 7:35
• @HenrikSchumacher I am not able to use f[1,2] after function definition. it is evaluating to itself. – Ali Hashmi Dec 10 '17 at 8:20
• 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];? – Henrik Schumacher Dec 10 '17 at 8:36
• Instead of addDownValuesRuntime[f, a1, a2,..., b]], why not f[a1, a2,...] := b? – Michael E2 Dec 10 '17 at 16:41
• @MichaelE2 thanks ! was somehow challenging myself :) – Ali Hashmi Dec 10 '17 at 17:12

What is wrong with

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


?

• 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 – Ali Hashmi Dec 10 '17 at 17:08

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];
InternalWithLocalSettings[
SetAttributes[func,HoldAll],
SetDelayed[func[args],body],
Attributes[func]=old
]
]


str = "p"; int = 5;

DownValues[f]


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

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 *)

Block[{setdelayed = SetDelayed},
SetAttributes[setdelayed, HoldAll];
Apply[setdelayed,{func[GeneralUtilitiesHoldSymbolName /@ Unevaluated[args]] /.
GeneralUtilitiesHoldSymbolName[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} *)

• actually in the above code we do not need to even define setdelayed. SetDelayed works equally fine ! – Ali Hashmi Dec 10 '17 at 17:16
• Have you tried calling your f` with the new definition you added? – halirutan Dec 10 '17 at 17:29
• @halirutan seems to be working fine. let me add it – Ali Hashmi Dec 10 '17 at 20:31