5
$\begingroup$

I'm trying to modify Plus but am running into trouble with it being Listable:

ClearAll[f, g, h]
Attributes[f] = {Listable};
h /: f[x_h, l_List] := 0
h /: g[x_h, l_List] := 0
f[h[1], {1, 1}]   (* {f[h[1], 1], f[h[1], 1]}, not OK I want 0 *)
g[h[1], {1,1}]    (* 0 as expected *)

How can I make the UpValue (or equivalent) have higher priority than the listability?

EDIT: I ended up wanting to do this again and figured I'd fix the Plus properly. Here it is working using Sashas answer and Mr.Wizards $Pre method:

    $Pre =.
ClearAll[myPlus]; Attributes[myPlus] = {Orderless};
Unprotect[InterpolatingFunction]; UpValues[InterpolatingFunction] = {};
InterpolatingFunction /: 
 myPlus[y_InterpolatingFunction[t_Symbol], l_List] := 
 Interpolation[
   MapThread[List, {y["Grid"], l + # & /@ y["ValuesOnGrid"]}], 
   InterpolationOrder -> First[y["InterpolationOrder"]]][t]
myPlus[other__] := +other
$Pre = Function[x, Unevaluated@x /. Plus -> myPlus, HoldAllComplete];
    Protect[InterpolatingFunction];

    y = Interpolation[Table[{i, RandomReal[{0, 1}, 2]}, {i, 1, 10}]];
    ParametricPlot[{y[t], y[t] - {1, 1}}, {t, 1, 10}]
$\endgroup$
5
  • $\begingroup$ You can't do that, or I'll be very surprised. Change your design somehow. It's hard to help in that without knowing a little bit about the bigger picture. Perhaps for your case adding the "listability" as e:f[_, l_List]:=Thread@Unevaluated@e or something similar, but that depends on the case at hand $\endgroup$
    – Rojo
    Feb 5, 2013 at 13:55
  • $\begingroup$ Oh, f is Plus, my bad. $\endgroup$
    – Rojo
    Feb 5, 2013 at 13:57
  • $\begingroup$ Yes, I agree. Not possible (I even tried with $Pre and $Post to fool the evaluator, but you cannot do that). Just program Listable like f[x_, l_List] := Thread[f, {x, l}]; and all is good. $\endgroup$ Feb 5, 2013 at 14:01
  • $\begingroup$ @Rojo Updated with bigger picture $\endgroup$
    – ssch
    Feb 5, 2013 at 15:37
  • 1
    $\begingroup$ I think this is one of these things which are really hard to make different generally and consistently, since one would have to explicitly go against the standard evaluation sequence. I would reconsider the design of whatever you try to achieve with this. While I will be the first to suggest workarounds which change system's behavior in many cases, I also think that admitting and accepting certain limitations of the system can sometimes be more productive. $\endgroup$ Feb 5, 2013 at 20:48

2 Answers 2

3
$\begingroup$

This seems disgusting, but here it goes

h /: Plus[x_h, l_List] :=
 withPlusListability[True][

  blabla; 0
  ]

withPlusListability[bool_: True | False] := Function[code,
   Internal`InheritedBlock[{Plus},
    Unprotect[Plus];
    If[bool, SetAttributes, ClearAttributes][Plus, Listable];
    code
    ], HoldFirst];

withH = withPlusListability[False];

So

withH[
  Print[h[3] + {4, 5}];
  Print[h[3] + 7];
 ];

prints

(*
0
7+h[3]
*)

While you evaluate code iniside withPlusListability[True|False], it takes care that Plus has|doesn't have the Listable attribute, without changing it globally. h's definition will only have a chance of matching with an unlistable Plus.

Plus is one of those symbols that are so special you really try not to mess with. As @Mr.Wizard warned, this will likely break for packed arrays, because it probably has been optimized to cut some corners.

$\endgroup$
3
  • $\begingroup$ @MrWizard, surprisingly, h[3] + RandomReal[{-1, 1}, 10]; works. Could you try it in v7? $\endgroup$
    – Rojo
    Feb 5, 2013 at 14:31
  • $\begingroup$ Cool, didn't know about Internal`InheritedBlock $\endgroup$
    – ssch
    Feb 5, 2013 at 15:56
  • $\begingroup$ Rojo: yes, it works. I need to take a closer look at this. $\endgroup$
    – Mr.Wizard
    Feb 6, 2013 at 1:28
3
$\begingroup$

Contrary to Rolf Mertig's comment I believe $Pre does work.

First define your function:

h /: myPlus[_h, _List] := 0
myPlus[other__] := +other

Then set $Pre:

$Pre = Function[x, Unevaluated@x /. Plus -> myPlus, HoldAllComplete];

Test:

h[1] + {4, 5, 6}
0
z[1] + {4, 5, 6}
{4 + z[1], 5 + z[1], 6 + z[1]}
$\endgroup$
9
  • $\begingroup$ @RolfMertig is pessimistic (comments) these days $\endgroup$
    – Rojo
    Feb 5, 2013 at 14:36
  • 2
    $\begingroup$ +other!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! HAAAAAAAAAAA +1 $\endgroup$
    – Rojo
    Feb 5, 2013 at 14:39
  • $\begingroup$ You make it look so easy, thanks! $\endgroup$
    – ssch
    Feb 5, 2013 at 15:59
  • $\begingroup$ @Rojo I'm afraid I don't understand your outburst. Unintentional humor? Does "plus other" mean something in contemporary parlance? $\endgroup$
    – Mr.Wizard
    Feb 5, 2013 at 16:36
  • $\begingroup$ @ssch Glad I could help. :-) $\endgroup$
    – Mr.Wizard
    Feb 5, 2013 at 16:37

Your Answer

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

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