MathGroup Archive 1991

[Date Index] [Thread Index] [Author Index]

Search the Archive

pipes in Mathematica

  • To: mathgroup at yoda.ncsa.uiuc.edu
  • Subject: pipes in Mathematica
  • From: jacobson at cello.hpl.hp.com
  • Date: Tue, 13 Aug 91 09:51:29 PDT

I use Mathematica a lot for data analysis.  I like to use a functional
programming style, but I have found this is more difficult in
Mathematica than it ought to be.  The problem is that when using
functional programming, particularly in data analysis, we are usually
starting with some list of values, and passing it successively through
a sequence of operations.  The problem is that some functions, such as
Select, Take, Drop, and Transpose, have their "data" or "expr"
argument first and their control arguments last.  So you get into this
situation of

Drop[
<<< giant 12-line function>>>,
     2]

and sometimes that is embedded in something bigger.  It is very
difficult to tell that the "2" goes with the drop.  

For a possible solution, let us look at the tremendously successful
pipe notation of the Unix C-shell.  

foo a | grep math | cut -2 | sort

This means start with foo a, and pipe its result into grep math, and pipe
its result into cut -2 and pipe is result into sort.  Mathematica can
do the same thing, but only if the functions (after the first) take exactly
one argument.  For example:

foo[a,b,c]//Fourier//Reverse

At some small runtime expense we can make this work with functions of all
types

foo[a,b,c]//Fourier//Drop[#,3]&//Map[1+1/#&,#]&

Note that the last thing in the pipe got confusing because there are 2
#s close to each other that mean different things.  (Maybe we could
write .../Map[Function[x,1+1/x],#]&, but it is more verbose and looks
confusing to me.)

To overcome this, I have developed a hack that is working quite well
for me.  


$$$/: Literal[f_[left___,$$$,right___]] := Function[x,f[left,x,right]

This lets me write the above as

foo[a,b,c]//Fourier//Drop[$$$,3]//Map[1+1/#&,$$$]

where $$$ appearing in a top-level argument causes the expression to
be converted to a function that accepts its input in that position.

Note that only one $$$ is allowed.  You must also be careful with
using this in infix expressions, since what looks like a top-level
parameter is not always.  For example foo // 2/$$$ // bar
would not do the right thing.

If you want to put this into a file that you read in, you will have
trouble if you reread the file.  This what I actually use.

=====================
$$$Switch=False

Unprotect[$$$]

$$$/: Literal[f_[left___,$$$,right___]] := Function[x,f[left,x,right],
	{HoldAll}]/; $$$Switch

(* The HoldAll attributed keeps the Function from evaluating its argument,
but normally, f will evaluate it anyway.  This maintains exact compatibility
with the normal function calling semantics. *)

Protect[$$$]

$$$Switch=True
===================
I'm using 2.0beta3.  Version 1.2 does not do true static scoping of
varibles, so 1.2 users may wish to change "x" above to something like
"Private`x" to be safe.  They will also have to drop the {HoldAll}
parameter.

I'm hoping to find a scheme that is less of a hack than this.  I would
really like a system with a new symbol, such as /// that would mean
"turn the thing to the right into a function and pipe the stuff to the
left into it."  Some special symbol, such as ###, would designate the
formal parameter, which would not have to appear at the top level, and
possibly might appear more than once.  The construct should work
properly when nested.  Suggestions are welcome.

  -- David Jacobson






  • Prev by Date: Re: Fortran Format
  • Next by Date: Mma 2.0 slower than 1.0?
  • Previous by thread: Re: Fortran Format
  • Next by thread: Mma 2.0 slower than 1.0?