32

All the cool kids are apparently using

##&[]

for

Unevaluated @ Sequence[]

but I have no idea what either means.

Please explain what these things are so I can be a cool kid!

orome
  • 12,819
  • 3
  • 52
  • 100
  • 1
  • p.s. you are so cool I can't even say your name! – Kuba Apr 02 '15 at 20:14
  • 4
  • This is the answer: 3705 but question is not really a duplicate so I don't know. – Kuba Apr 02 '15 at 20:20
  • 1
    @Kuba: For reference, this is helpful too. – orome Apr 02 '15 at 20:23
  • @raxacoricofallapatorius that's definitely evil. My favorite, though, is from classic who: Romana. – rcollyer Apr 02 '15 at 20:24
  • 2
    Am I the only one who saw this in the "hot network questions" and wondered at first what the (%# mathematica to do with $&%ing grawlixes? – neminem Apr 02 '15 at 23:41
  • Read about The Standard Evaluation Sequence and Nonstandard Evaluation here. This should be a good start. Unevaluated, Sequence and Evaluate are a bit special and are not handled in the usual way during the evaluation procedure. – Szabolcs Apr 03 '15 at 01:43
  • 5
    I am not extemely keen on ##&[]. It is concise (and I think clear enough after one understands it), but Function invocation is not the fastest operation in Mathematica. In most cases (except where the subtle differences actually matter), I would prefer Unevaluated@Sequence[] for explicitness and avoiding an unnecessary function call. Simon Woods's suggestion of Unevaluated[] could be the best compromise. – Oleksandr R. Apr 03 '15 at 14:37
  • Ha! I somehow missed this question until now. I love seeing this get more attention but I think this needs to be closed as a duplicate; it is well explained in my existing answer. Congratulations on a Good Question badge. :-) – Mr.Wizard Apr 08 '15 at 16:44
  • @Oleksandr You can see that I included Unevaluated[] in this answer. Performance was briefly discussed with Leonid in the original dialog (on Stack Exchange) about this. To address your concern I shall add benchmarking to my answer. – Mr.Wizard Apr 08 '15 at 16:50
  • @rax By the way there was a link to 3705 in the "cool kids" comment all along. I guess I should try to make those more visible. – Mr.Wizard Apr 08 '15 at 16:52
  • 1
    @Kuba For some time now the close text has read This question already has an answer here: which makes it reasonable to close in cases such as this. – Mr.Wizard Apr 08 '15 at 16:53
  • @Mr.Wizard: So the duplicate text should say "or already has an answer". – orome Apr 08 '15 at 17:10
  • 1
    @OleksandrR. ## &[] tests as slightly faster than Unevaluated[] in both 7.0 and 10.0. Please see the update to answer 3705. – Mr.Wizard Apr 08 '15 at 17:34
  • @Mr.Wizard thanks for doing this test. That will teach me for assuming Unevaluated[] would perform exactly the same as Unevaluated@Sequence[]! The vanishing function is also not as slow as I had anticipated; its 10-20% penalty over Unevaluated@Sequence[] is quite tolerable for most applications. – Oleksandr R. Apr 08 '15 at 18:39

2 Answers2

23

Try this:

Map[If[#==1,Unevaluated@Sequence[],#]&,{1,2,3}]

Note the output. The 1 is gone. That's because Unevaluated@Sequence[] puts the empty sequence there, that is, "nothing".

##&[] is a shorthand that can be used in most places for same - ## is the sequence of arguments, & makes it a function to apply to something, [] is that something - an empty argument list, so the result is... a sequence that is empty.

ciao
  • 25,774
  • 2
  • 58
  • 139
  • This is great. I think this is what I was looking for (in a question that actually almost answers this one, and is a dupe of the one @Kuba mentions above — failing memory!) years ago: something to put in If or Which when I wanted "nothing". – orome Apr 02 '15 at 20:35
  • 4
    Good explanation. I prefer Unevaluated[] to Unevaluated@Sequence[] though I can see why the latter might be considered clearer. – Simon Woods Apr 02 '15 at 21:19
  • 1
    So the bottom line is that all these 3 do the same thing: Map[If[# == 1, Unevaluated@Sequence[], #] &, {1, 2, 3}]; If[# == 1, Unevaluated@Sequence[], #] & /@ {1, 2, 3}; If[# == 1, ## &[], #] & /@ {1, 2, 3}; so use the last one above. It is not only shorter than all the others, but also makes you look much smarter as well. – Nasser Apr 02 '15 at 21:48
  • 1
    @Nasser: Yeah If[# == 1, ## &[], #] & /@ {1, 2, 3}; — I mean, obviously! – orome Apr 02 '15 at 21:52
  • @SimonWoods: Is Unevaluated[] the same as Unevaluated@Sequence[]? – orome Apr 03 '15 at 01:19
  • 3
    @raxacoricofallapatorius you can also write If[# == 1, Sequence @@ {}, #] & /@ {1, 2, 3} which gives {2, 3} also. but from now on, I will use ##&[] to be more cool. – Nasser Apr 03 '15 at 01:24
  • @raxacoricofallapatorius, it works the same in most places that you'll see Unevaluated@Sequence[], but I hesitate to say that it's equivalent. There may be counterexamples. – Simon Woods Apr 03 '15 at 15:43
8

I believe it is important to get a fundamental understanding of what Pure Functions are that goes beyond the understanding using of a syntax. Hereafter an non-exhaustif summary of a few key understandings:

1) Pure Functions have they roots in Lambda calculus that forms the basis of functional programming paradigm implemented in Mathematica.

2) In Mathematica a Pure Function is simply an expression with the head Function that is applied to arguments.

3) Syntactially # represent a slot for arguments, whereas ## represent a sequence of arguments

4) Syntactially & represents an operator for declaring an expression as a Pure Function

5) Pure Functions have no names and therefore do not create any global defintion in Mathematica (in Lambda calculus also called anonymos functions)

6) Pure Function can be used within other expressions.

Example to point 2)

 Head[# &]
(* Function *) 

Applying a Pure Function to an argument

 Sqrt @ # &[4]
(*2*)

this is equivalent to writing

Function[x,Sqrt @ x][4]
(*2*)

Example to point 3) difference between supplying the first argument or a sequence of arguments

Plus@# &[1, 2, 3]
(*1*) 
Plus@## &[1, 2, 3]
(*6*)

PS:easy or not? even penguins would understand this..hi,hi

Unevaluted simply holds evaluation of an expression within an argument. Rasher's example demonstrates this well.

Regarding your comment, the difference between ##&[] and Unevaluated @ Sequence[] in the example from Rasher is that

a) ##&[] is short notation for Function[SlotSequence[1]][], which is evaluated to Sequence[], which then is spliced into the result {2,3}.

whereas

b) the kernel evaluates Unevaluated @ Sequence[] to Sequence[] after the function If[] has been evaluated, which is then spliced into the final result {2,3}.

Therefore due to the sequence of the evaluation process ##&[] is Unevaluated@Sequene[] and not Sequence[].

Using Trace and FullForm are powerful "tools" if you would like to go "playing in the league of cool kids". They reveal how short notation is re-written and give insight into the evaluation process.

I would recommend to compare output of following in order to get better insight:

Trace[If[# == 1, ## &[], #] & /@ {1, 2, 3}]  // FullForm

Trace[If[# == 1, Unevaluated @ Sequence[], #] & /@ {1, 2,3}] // FullForm 
penguin77
  • 1,645
  • 9
  • 8
  • This penguin doesn't understand the last bit, about Unevaluated: ## &[1, 2 + 2, 3] is Sequence[1, 4, 3], so 2+2 got evaluated, right? If so, how is ## &[] Unevaluated@Sequence[] and not Sequence[]? – orome Apr 03 '15 at 01:18
  • @ raxacoricofallapatorius, following your comment I have extended my answer. However the short answer is that It is because of the sequence of the evaluation process that ##&[] is Unevaluated@Sequene[] and not Sequence[] – penguin77 Apr 03 '15 at 19:10
  • @ raxacoricofallapatorius, I made small corrections for better understanding.....vote for penguins... – penguin77 Apr 04 '15 at 09:02