1
$\begingroup$

One can write functions which depend on the type of actual parameter before they are actually called. E.g.:

Clear[f,g,DsQ]; DsQ[x_]:=MatchQ[x,{String__}]; f[i_Integer, ds_?DsQ] :=Print["called with integer i and DsQ[ds]==True"]; f[i_String, ds_?DsQ] :=Print["called with String i and DsQ[ds]==True"]; f[i_?NumberQ, ds_?DsQ]:=Print["called with numerical parameter"]; f[i_?NumberQ]:=Print["only a numerical parameter"]; (* Tests *) ds={"string"}; DsQ[ds] f[1,ds] f[1.,{""}] f[999] 

yields

True called with integer i and DsQ[ds]==True called with numerical parameter only a numerical parameter 

Now I want to write another function g, which gets a function like f as parameter. But the functional parameter’s definition’s left hand side shall have a defined form, e.g. only the one from the first definition of f

f[i_Integer, ds_?DsQ] 

Is such a check for the right pattern of a functional parameter possible? How do I do that? Writing

g[p_Symbol[i_Integer, ds_?DsQ]]:=Print["g called with first type of definition"] 

does not work.

$\endgroup$
9
  • 1
    $\begingroup$ It's not quite clear to me what you want to achieve: How do you want to call g? As g[f]? What should happen if f has multiple different definitions (like in your example)? What do you ultimately want to use this for? $\endgroup$ Commented Dec 14, 2022 at 22:39
  • 1
    $\begingroup$ I think what you want is to set attributes of g so that it holds its argument. Something like SetAttributes[g, HoldAll]. Try it out and see if it works: g[f[1, {""}]] prints "g called with first type of definition" but g[f[0.1, {""}]] returns unevaluated. If that's what you want, I can write a quick answer. $\endgroup$ Commented Dec 14, 2022 at 23:09
  • $\begingroup$ I agree with @LukasLang that this looks like an XY problem. If you could describe in detail what you are trying to achieve (at high level), then you’ll likely get better answers. $\endgroup$ Commented Dec 15, 2022 at 13:47
  • $\begingroup$ Since you tried g[p_Symbol[i_Integer, ds_?DsQ]] instead of g[f[i_Integer, ds_?DsQ]], I'm inferring that what you mean by "type" is something like signature. Is that correct? I.e. the function g doesn't actually know about the function f explicitly, but will do something for any p that has a particular signature. If this is on the right track, it would be very helpful to have more context. What do you need g to do with p and with the arg pattern? $\endgroup$ Commented Dec 15, 2022 at 15:30
  • $\begingroup$ I ask, because as it stand, I don't think you can come up with something generally resilient. For example, one can't expect f[i_Integer, ds_?DsQ] to be a sort of canonical form for that signature. Indeed, something like f[i_Integer, ds : {__String}] might be more expected. $\endgroup$ Commented Dec 15, 2022 at 15:34

3 Answers 3

0
$\begingroup$

The call patterns are stored under the name of "DownValues":

DownValues[f] 

enter image description here

Therefore, the part that determines the type can be extracted by:

DownValues[f][[1, 1, 1, 2]] 

enter image description here

and you can define g e.g. like:

g[i_ : Integer, DownValues[f][[1, 1, 1, 2]] ] := Print["g called with integer and string-list"] g[1, {"y"}] (* g called with integer and string-list *) 
$\endgroup$
2
  • $\begingroup$ Daniel, somehow you mistyped something which prevents me from seeing the clue which was about to follow your last colon. $\endgroup$ Commented Dec 15, 2022 at 16:38
  • $\begingroup$ Sorry, I added the missing piece. $\endgroup$ Commented Dec 15, 2022 at 17:52
0
$\begingroup$

Here's a suggestion that differs from your approach but may be useful. For every function (here, f and h) we define a "correct" interface and a "catchall" interface that is used whenever the function is called incorrectly. The "catchall" interface (with the pattern x___) aborts the running calculation.

Clear[f, g, h, DsQ]; DsQ[x_] := MatchQ[x, {String__}]; f[i_Integer, ds_?DsQ] := Print["f called with integer i and DsQ[ds]==True"]; f[x___] := Module[{}, Print["f called with different arguments: ", {x}]; Abort[]] h[i_Integer] := Print["h called with integer i"]; h[x___] := Module[{}, Print["h called with different arguments: ", {x}]; Abort[]] g[p_Symbol] := p[7, {"a"}] + p[8, {"b"}] + p[9, {"c"}] 

We can use f to call the function g:

g[f] (* f called with integer i and DsQ[ds]==True f called with integer i and DsQ[ds]==True f called with integer i and DsQ[ds]==True 3 Null *) 

But we're not allowed to use h to call the function g:

g[h] (* called with different arguments: {7,{a}} $Aborted *) 

Of course your action in the "catchall" may be different from Abort[].

$\endgroup$
0
$\begingroup$

These examples show better which expression causes a specific print line than in my original post:

ClearAll[f,g,DsQ]; DsQ[x_]:=MatchQ[x,{String__}]; f[x___] := (Print["f: called with illegal arguments f[", x, "]"]; Abort[]); (* added catch all, tx Roman *) f[i_Integer, ds_?DsQ] := (Print["f: called with integer ", i, " and DsQ[ds]==True"]; "Result: "<>ToString[i]<>", "<>ToString[ds]); f[s_String, ds_?DsQ] := (Print["f: called with String ", s, " and DsQ[ds]==True"]; "Result: "<>s<>", "<>ToString[ds]); (* Tests *) ds={"string ds"}; DsQ[ds] f[1, ds] f["hello", ds] 

yields

True f: called with illegal arguments f[forbidden!] $Aborted f: called with integer 1 and DsQ[ds]==True Result: 1,{string ds} f: called with String hello and DsQ[ds]==True Result: hello, {string ds} 

The other function g gets a function like the first form of f as parameter. The functional parameter’s definition’s left hand side shall have a defined form, e.g. only the one from the first definition of f

f[i_Integer, ds_?DsQ] 

and not e.g. the other way around like

h1[ds_?DsQ, i_Integer] 

or

h2[i_Integer, j_Integer] 

or any form of f but the first one.

This is the appropriate pattern for the functional parameter on the LHS:

g[p_Symbol[i_Integer, ds_?DsQ]]:=Print["g: called with first type of definition, f returns ", f[i, ds]]; 

In this one

g[f[3, {"three"}]] 

f is evaluated first and returns a string. We see the Print from f and the unevaluated expression of g with the result from f which does not match g's definition pattern, therefore we get:

g[Result: {three}]] 

But after setting HoldAll it works:

SetAttributes[g, HoldAll] g[f[4, {"four"}]] 

It prints

f: called with integer 4 and DsQ[ds]==True g: called with first type of definition, f returns Result: 4, {four} 

which is what I was after.

$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.