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$
9
  • 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$
    – vapor
    Mar 10, 2017 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$ Mar 10, 2017 at 14:53
  • 1
    $\begingroup$ Can you tell me in what cases Thread does not work? $\endgroup$
    – vapor
    Mar 10, 2017 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, 2017 at 9:21
  • $\begingroup$ If performance is relevant then How can one write a robust ListableQ function? might be related. $\endgroup$
    – jkuczm
    Mar 11, 2017 at 9:35

1 Answer 1

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$
13
  • $\begingroup$ Ah right, of course Module works nicely. However, other solutions would be interesting, too (if they exist) $\endgroup$ Mar 10, 2017 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, 2017 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, 2017 at 14:53
  • $\begingroup$ @rcollyer that is a very nice solution! $\endgroup$
    – Stitch
    Mar 10, 2017 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$ Mar 10, 2017 at 14:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.