8

For example, for a built-in function in Mathematica, f, originally f[1] gives {1,2,3}, but I want to let Mathematica gives only {1,3}. A simple method for rewritting f is desired. I don't want to define a new function or totally rewrite f or just dealing with original f's outputs. I want to rewite f.

Thanks. :)

FreshApple
  • 592
  • 3
  • 14
  • `$Post` seems to be an good way, but it applies to all built-function which is not I want? – FreshApple May 20 '11 at 14:58
  • 1
    `$Post` is applied to every output expression as it is clearly stated in the documentation. It knows nothing on how this expression was generated. – Alexey Popkov May 20 '11 at 16:01
  • In you example, do you mean `f[1]` gives `{1,2,3}`, or do you mean something like `f /@ {3, 5, 7}` gives `{1,2,3}`? I ask because `Sin` gives a single numerical output, not a list. – Mr.Wizard May 20 '11 at 21:26
  • 2
    There are some solutions below, but it's really asking for trouble mucking with system symbols. It's much better to write a new function mySin[], calling the built in Sin[] and altering the output before returning. – Joshua Martell May 22 '11 at 04:25

4 Answers4

11

You can use the Villegas-Gayley trick for this.

For the Sin function:

Unprotect[Sin];
Sin[args___]/;!TrueQ[$insideSin]:=
   Block[{$insideSin=True,result},
      If[OddQ[result=Sin[args]],result]
   ];
Protect[Sin];
{Sin[Pi],Sin[Pi/2]}

==> {Null,1}
Community
  • 1
  • 1
Alexey Popkov
  • 9,355
  • 4
  • 42
  • 93
  • @Sjoerd:Your answer is what I have looking for for a really long time. Sorry for the late response. :( and Many, many thanks for this brilliant hacking method! :) – FreshApple May 22 '11 at 10:59
  • @Fresh Actually, the above was written by Alexey who was referring to a trick we have been using quite a lot here since it was published in the Mathematica toolbag question (http://stackoverflow.com/questions/4198961/what-is-in-your-mathematica-tool-bag/5149656#5149656). – Sjoerd C. de Vries May 22 '11 at 17:54
6

I prefer a method which is functional and reminds me of decorators in Python. http://wiki.python.org/moin/PythonDecorators

First we create the decorator:

OddOnly[x_] := If[OddQ[x], x, Null];

It can then be used as a prefix:

OddOnly@
 Sin[Pi]

Null (* Doesn't actually give a result *)

OddOnly@
 Sin[Pi/2]

1
Searke
  • 779
  • 3
  • 3
6

A variation of Searke's method that I prefer is:

OddOnly[s_Symbol] := 
 Composition[If[OddQ@#, #, ##&[]] &, s]

This automatically removes results that are not odd, and it is applied to the function itself, which I find more convenient.

Examples:

OddOnly[Sin] /@ {2, Pi, Pi/2}

(*  Out[]= {1}  *)

Array[OddOnly[Binomial], {5, 5}]

(*  Out[]= {{1}, {1}, {3, 3, 1}, {1}, {5, 5, 1}}  *)
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
  • 5
    Nice idea - +1. Since I know about your passion for terseness, let me point out that the effect equivalent to `Unevaluated@Sequence[]` inside `If` (or any head that is `Hold*` but not `SequenceHold`) can be achieved also with `Sequence@@{}`. – Leonid Shifrin May 22 '11 at 13:45
  • @Leonid that is a great tip! I wish I had thought of that; it makes perfect sense. – Mr.Wizard May 23 '11 at 00:17
  • @Leonid, interestingly, that short form comes with a small performance penalty. – Mr.Wizard May 23 '11 at 00:26
  • @Mr.Wizard Yes, sure, there is a little performance penalty. But I haven't yet seen a single use case for it where this would be noticeable, let alone be the major bottleneck. – Leonid Shifrin May 23 '11 at 08:38
  • @Leonid, I did notice the difference in the first place I tried it. ;-) Nevertheless, I was mostly remarking on the fact that it was slower, which I could not predict before trying it; `Sequence @@ {}` seems very simple, why should there be any performance penalty? (Please do not think that because of this slight penalty, I am any less grateful for your tip!) – Mr.Wizard May 23 '11 at 08:49
  • 1
    @Mr.Wizard The penalty is because it is one evaluation more, I think. `Unevaluated` gets stripped by the evaluator, without any sub-evaluation induced. But `Apply[Sequence,{}]` must undergo a separate evaluation. May be, there are other more subtle reasons that I am not aware of, as well. – Leonid Shifrin May 23 '11 at 09:34
  • 1
    @Leonid, appreciate your thoughts. Interestingly, if I set `vanish[] := Sequence[]` and then use `vanish[]` it is almost as fast as `Unevaluated@Sequence[]`; faster than `Sequence @@ {}`. – Mr.Wizard May 23 '11 at 09:54
  • 1
    @Mr.Wizard This seems logical. Before I became aware of `Sequence@@{}`, I was using `1/.(1:>Sequence[])` or something similar, which is a local version of your `vanish`. I think, in part the speed gain here is due to `RuleDelayed` (and `SetDelayed`) being `SequenceHold`. Simply rewriting is faster than inducing (sub)evaluation, which is what happens with `Apply`. – Leonid Shifrin May 23 '11 at 10:11
  • 2
    @Leonid, today in my notes I found an even shorter form: `##&[]` I wish I was half as retentive as I am clever. ;-) – Mr.Wizard Oct 28 '11 at 09:04
4

Could apply a rule of the form

whatever /. _Integer?EvenQ :>Sequence[]

Daniel Lichtblau

Daniel Lichtblau
  • 6,854
  • 1
  • 23
  • 30