Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Mathematica allows to define pure function, like

Function[{a, b},Length[Unevaluated@a]{b}][1+2,2+3]
(*
==> {0}
*)

Pure functions in Mathematica can take an arbitrary number of arguments, but only if not naming them, for example:

Function[Length[Unevaluated@#1]{##2}][1+2,2+3,3+1]
(*
==> {0,0}
*)

Also, pure functions can optionally have attributes, for example:

Function[{a,b},Length[Unevaluated@a]{b},{HoldFirst}][1+2,2+3]
(*
==> {10}
*)

However what I haven't found is a way to have both arbitrary many arguments and attributes:

Function[(* what, if anything, to put here? *)][1+2,2+3,3+1]
(*
==> {10, 8}
*)

Therefore my question:

Is it possible to define pure functions which take an arbitrary number of arguments and at the same time have attributes? And if so, how would one define them?

The obvious solution doesn't work:

Function[Length[Unevaluated@#1]{##2},{HoldFirst}][1+2,2+3,3+1]
(*
Function::flpar: Parameter specification Length[Unevaluated[#1]] {##2} in 
Function[Length[Unevaluated[#1]] {##2},{HoldFirst}] should be a symbol or 
a list of symbols. >>
*)

Adding an empty parameter list disables parameter substitution for ##;

Function[{},Length[Unevaluated@#1]{##2},{HoldFirst}][1+2,2+3,3+1]
(*
==> {##2}
*)

Of course, a workaround is easy; for example, have the pure function take a list (which in the example above would actually have been the better alternative anyway), or simply using a named function. So it's more of a curiosity. It just seems odd to have two completely orthogonal features of pure functions, and yet not being able to combine them.

share|improve this question
    
You could do something like Function[, ##, <Attributes>], for instance. Is that what you were asking? – R. M. Jul 25 '13 at 17:25
3  
Try Function[, {Unevaluated@#, Unevaluated@#2}, HoldFirst][2 + 2, 2 + 2]... – ciao May 26 at 22:17
4  
Attributes are documented now: ["Function[params,body,{attr1,attr2,…}] represents a pure function that is to be treated as having attributes for the purpose of evaluation."](reference.wolfram.com/language/ref/Function.html). HoldAll and Listable are used in the examples. – Karsten 7. May 26 at 22:30
1  
@Karsten7.- the attributes have been documented for a long time, I think the OP means in the context of using them with Slots for arguments. – ciao May 26 at 22:39
1  
No, I meant what @ciao mentioned. This is a different form from what was mentioned by Karsten_7. – Leonid Shifrin May 27 at 9:10
up vote 17 down vote accepted

Yes, this form exists, and was first shown to me by Leonid. It is:

Function[Null, (* body with ## *), (* attributes *)]

As always the Null may be implicit, so in your application:

Function[, Length[Unevaluated@#1]{##2}, HoldFirst][1+2,2+3,3+1]
{10, 8}
share|improve this answer
7  
+1. To be pedantic, I will add that this form is undocumented (but very unlikely to be discontinued). – Leonid Shifrin Jul 25 '13 at 18:02

This is the answer merged from this more recent question

The form in question

I meant the form

Function[Null, body-using-slots, attrs]

as ciao correctly noted.

At least at the time when I wrote the book, this form hasn't been documented. I learned about it from Roman Maeder's book "Programming in Mathematica". OTOH, this form is very useful in some cases, particularly with Hold - attributes.

Use cases

I can think of two major classes of use cases for this form

  • Cases, when we could get away with using named arguments, such as

    Function[{x,y}, x = y, HoldFirst]
    

    but prefer not to, because of scoping problems / leaks associated with this form. Basically, the mentioned leak makes passing such functions into other functions generally unreliable. And it does happen in practice, I was bitten by this many times, most recently just a couple of weeks ago. This problem isn't there for Slot - based functions, although the latter have more limited nesting capabilities.

    Note, however, that in modern versions of Mathematica, a new system option "StrictLexicalScoping" is available, thanks to Daniel Lichtblau, which solves this problem. But, for certain reason, it is not yet a default, and if you write code for others, you probably can't count on it being set to True on their machines, so having alternatives is still useful. This option has been discussed a few times here on SE.

  • Cases, where we don't know the number of arguments in advance, and also where this number may not be fixed, but varies from call to call. Here is an example of such a function, written by Mr.Wizard in this answer: it computes the length of passed first argument, without evaluating it, and multiplies the list of rest of the arguments by it:

    Function[Null, Length[Unevaluated@#1]{##2}, HoldFirst]
    

A few more examples

Here is another general example I found, from the question MapThread with non-rectangular lists, the solution given by Rojo:

Function[Null, f[##], Listable] @@ A

I also found a couple of my own posts containing this form: here I used it in this block of code:

MapThread[
   Function[Null, Hold[#1 = #2], HoldAll],
   Unevaluated @ {vars, vals}
]

which generates held assignments to variables without evaluation leaks, and here, where the following pattern

s_?(Function[Null, ListQ[Unevaluated[#]], HoldAll])

was used to test for an argument having the head List, without evaluating it.

Summary

The form in question is

Function[Null, body-using-slots, attrs]

which is really useful in a number of circumstances. The use cases for it divide into two large categories:

  • Cases where Function with named arguments can be used in principle, but we still prefer the slot-based function. One of the main reasons for this is to avoid lexical scoping issues.

  • Cases where Function with named arguments can not be used even in principle, simply because the number of arguments is unknown at function's construction time, or can vary from call to call.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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