3
$\begingroup$

I have a function taking a function as input as well as other values, e.g.

f2[f_, a_, b_, c_, d_] = f[{a, b}, c, d];

Of course, the behavior differs for f1 being Listable or not. So if I define

f1[x_, y_, z_] = If[x > 0, x*y + z, -x + y + z]

it will yield

In= Attributes[f1] = {};f2[f1, 1, 2, 3, 4]
Out= If[{1, 2} > 0, {1, 2} 3 + 4, -{1, 2} + 3 + 4]

in contrast to

In= SetAttributes[f1, Listable]; f2[f1, 1, 2, 3, 4]
Out= {7, 10}

.

Now my question is: can I implement that f2 will always treat the given input function as Listable? So that I don't have to explicitely give the Attribute to the input function beforehand and still get the listable-ish output (in this case {7,10}.

I was trying

f3[f_, a_, b_, c_, d_] = Assuming[Element[Listable, Attributes[f]], f[{a, b}, c, d]];

but this behaves exactly like f2.

(Of course, in this simple case, I could map over the list {a,b} but let's assume this is not possible or not convenient.)

$\endgroup$
  • 2
    $\begingroup$ Why not use Thread? Listable is just an automatic Thread. f3[f_, a_, b_, c_, d_] = Thread[f[{a, b}, c, d]]; $\endgroup$ – happy fish Mar 10 '17 at 14:48
  • $\begingroup$ Right, this works, but I didn't come up with it because Thread didn't work in a similar though slightly different context $\endgroup$ – riddleculous Mar 10 '17 at 14:53
  • 1
    $\begingroup$ Can you tell me in what cases Thread does not work? $\endgroup$ – happy fish Mar 10 '17 at 16:17
  • $\begingroup$ What do we know about a, b, c, d arguments? Can they be lists themselves? Do you want f function to thread them simultaneously with list you create in f2 body? Explicit mapping is safest in this respect, since it won't accidentally thread where you don't want it. $\endgroup$ – jkuczm Mar 11 '17 at 9:21
  • $\begingroup$ If performance is relevant then How can one write a robust ListableQ function? might be related. $\endgroup$ – jkuczm Mar 11 '17 at 9:35
3
$\begingroup$

If you don't want to modify f1 globally, then you can do it locally:

ClearAll[f1, f2listable];
f1[x_, y_, z_] := If[x > 0, x*y + z, -x + y + z]
f2listable[f_, a_, b_, c_, d_] := 
 Module[{g}, g[x_, y_, z_] := f[x, y, z]; SetAttributes[g, Listable]; g[{a, b}, c, d]]

f2listable[f1, 1, 2, 3, 4]

{7, 10}

$\endgroup$
  • $\begingroup$ Ah right, of course Module works nicely. However, other solutions would be interesting, too (if they exist) $\endgroup$ – riddleculous Mar 10 '17 at 14:42
  • $\begingroup$ @riddleculous You mentioned in the OP you are not willing to use any of the functions that apply functions over lists. What is the reason for this? $\endgroup$ – Stitch Mar 10 '17 at 14:52
  • 3
    $\begingroup$ For modifying attributes/general function behavior, I use Internal`InheritedBlock which acts like Block except the original behavior is still present, i.e. you can modify the existing behavior, temporarily. So, I would use f2listable[...] := Internal`InheritedBlock[{f1}, SetAttributes[f1, Listable]; f1[...]]. $\endgroup$ – rcollyer Mar 10 '17 at 14:53
  • $\begingroup$ @rcollyer that is a very nice solution! $\endgroup$ – Stitch Mar 10 '17 at 14:54
  • $\begingroup$ @Stitch because in my case, it's more complicated and I use Apply for other arguments of f1 which makes the use of Map impossible or at least very confusing here $\endgroup$ – riddleculous Mar 10 '17 at 14:55

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.