Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Recently I had the need to redefine a certain symbol in my init.m so it would be automatically omitted from any lists it appears in. I decided to redefine it to an empty sequence, e.g. Locked = Sequence[], but that got me thinking. What if I wanted to return a sequence (not necessarily an empty one) in a := definition? Return doesn't have the SequenceHold attribute, and adding it in a package might cause problems, so what would I do?

EDIT: I think I've figured out what exactly causes me to have the problem. I've defined it to display a Message first to let me know whenever a package I'm importing attempts to attack my computer. (It is trying to cause my computer to behave in a manner not consistent with my wishes, after all.) So I defined it as Locked := (Message[Locked::nope]; Sequence[]), but strangely it just returns Null. (It doesn't show a return value, but if I do {Locked}, it returns {Null}, and if I try to set it as an attribute it says that Null is not a valid attribute and doesn't set any of them.)

share|improve this question
3  
Locked is itself Locked in version 9, precisely to prevent people doing what you are trying to do here, which is the oldest trick in the book. ;) About the question, though: Return is rarely needed and you can anyway return results wrapped in any head that is either SequenceHold or HoldAllComplete to achieve what you want. I'd suggest Unevaluated as a reasonable choice, useful also for its habit of disappearing. –  Oleksandr R. Feb 3 '13 at 7:39
1  
Yes, I know Locked is locked in Mathematica 9, which is precisely why I keep a copy of Mathematica 8 installed on one computer. I believe I've tried using Unevaluated. Do you mean something like Return[Unevaluated[Sequence[]]]? If not, could you please give an example of what you do mean? By the way, take a guess what I used to prevent packages from erasing my definition of Locked. ;-) –  flarn2006 Feb 3 '13 at 10:24
1  
I mean, look at the answers below--nobody is using Return. It's really only necessary when you want to bail out of a construct like While that ordinarily wouldn't have any return value, or which wouldn't terminate except in the case of a manual return. If you encounter such a situation then Return@Unevaluated@Sequence[...] is indeed fine (though you might need the second argument of Return). Otherwise, just use Unevaluated@Sequence[...] in place of the usual return value (typically the last position of constructs such as CompoundExpression or Module). –  Oleksandr R. Feb 4 '13 at 2:37
2  
Re: your edit... what's the problem with Unevaluated@Sequence[] in this case? Incidentally if you consider the use of Locked to be malicious then I might suggest that the best course of action is not to use such packages in the first place. We have discussed this issue here before and the community concensus was that it harms us all to openly discuss how to circumvent Locked or Encode. Given the way this discussion is going, I would suggest removing that context or otherwise the question is likely to be deleted. –  Oleksandr R. Feb 4 '13 at 15:17
add comment

4 Answers

up vote 6 down vote accepted

Calculate the List of results you wish to return and use Apply to replace the head:

listFn[a_, b___] := If[a > 0, {b}, {0}];
seqFn[args___] := Sequence @@ listFn[args];
f[1, seqFn[2, 3, 4, 5], 6]
f[1, seqFn[-2, 3, 4, 5], 6]

(*--> f[1, 3, 4, 5, 6] *)
(*--> f[1, 0, 6] *)

Here listFn represents the calculation of the results and does not need to be a separate function. The particular example above can be written more simply as

seqFn[a_, b___] := Sequence @@ If[a > 0, {b}, {0}]

Edit

It should be stressed that the method assumes listFn actually evaluates to the List of desired inputs; if not, the Head of the expression returned will be replaced with Sequence, perhaps with undesired results. In such a case, a method such as @Jens's may be used.

For instance if a is non-numeric, say a Symbol, in the example above, then you get

f[1, seqFn[x, 3, 4, 5], 6]
(*-> f[1, x > 0, {3, 4, 5}, {0}, 6] *)

Often one can construct a List of the actual results, though. (With thanks to @Mr.Wizard.)

share|improve this answer
    
That's the easiest way, I think. –  Jens Feb 3 '13 at 16:30
    
This worked great for me. Thanks a lot! Accepted. –  flarn2006 Feb 4 '13 at 6:15
    
There is a problem with this method. Apply (@@) is used whether or not If evaluates, therefore if you enter x =.; seqFn[x, 1, 2, 3] you get Sequence[x > 0, {1, 2, 3}, {0}] which is wrong and confusing. You could force If to evaluate using TrueQ or the fourth argument but it would often be better if delayed evaluation was possible, as is the case with many built-in functions. To that end it's better and shorter to write: seqFn[a_, b___] := If[a > 0, ## &[b], {0}]. Now seqFn[x, 1, 2, 3] returns If[x > 0, (##1 &)[1, 2, 3], {0}] which is correct if x acquires a value later. –  Mr.Wizard Feb 4 '13 at 7:42
    
@flarn See my caveat above before you put this into use. –  Mr.Wizard Feb 4 '13 at 7:43
    
@Mr.Wizard Good point. I should probably stress in the answer that one has to have actually calculated the List. See edit. –  Michael E2 Feb 4 '13 at 13:17
show 3 more comments

To return a sequence using a SetDelayed function simply try

seqFu[] := Unevaluated[Sequence[]]

Or even

Clear[seqFu]
seqFu[args___] := Unevaluated[Sequence[args]];

But do not fall into the trap that even though for

seqFu2[args___]:= Unevaluated[args]

seqFu2[1,2]

-> Sequence[1,2]

you will have the unwanted

seqFu2[1]

-> 1

To return a sequence "on the fly",

Function[Null, #, SequenceHold][seq]

will just return your sequence seq. For example

Function[Null, #, SequenceHold][Sequence[]]

-> Sequence[]

I think generating empty sequences "on the fly" like this can maybe provide some nice way to write some functional code, especially tail recursion. I intend to use this soon, so maybe soon a link with an example will follow.

Note that you can also do

CompoundExpression[args, Unevaluated[Sequence[]]]

-> Sequence[]

Or

Identity[Unevaluated[Sequence[]]]
share|improve this answer
add comment

Maybe I've missed the point, but a sequence in most ways is just another Mathematica expression, so consider just returning a sequence.

f[args___] := args
g[x, f[a, b, c], y]

g[x, a, b, c, y]

g[x, f[], y]

g[x, y]

Update

I have edited this answer to incorporate Mr. Wizard's observation that args in f[args___] := args is already a sequence and doesn't need to be wrapped with Sequence.

share|improve this answer
1  
This can be written more simply: f[args___] := args. Sequence is automatically applied to the raw sequence args if no surrounding head is found. The advantage of Jens' method over either of these is in the case of SetAttributes[g, SequenceHold]. –  Mr.Wizard Feb 3 '13 at 14:54
    
@Mr.Wizard this seems more native to me than Jens's, and I vote this as the obvious #1 answer. That advantage doesn't seem big to me given that symbols with SequenceHold probably have that attribute for a reason. Furthermore, it could be in some cases less than the disadvantage of giving other upvalues the chance of "winning". Finally, there's also the possibility to do what Jens did but straight with Sequence, say Sequence /: (h : Except[If])[b___, HoldPattern@HoldPattern@Sequence[m___], a___] := h[b, m, a] –  Rojo Feb 4 '13 at 17:30
    
@Rojo I like this one too but I have been holding my vote hoping that Mr. Goldberg would amend his answer to use or at least include the shorter syntax I proposed. :^) –  Mr.Wizard Feb 6 '13 at 3:31
    
@Mr.Wizard. I made the change. I would have done it before except that I felt your comment counted as change :-) –  m_goldberg Feb 6 '13 at 5:32
1  
The change that you made is not what @Mr.Wizard meant mainly, hehe –  Rojo Feb 6 '13 at 9:30
show 2 more comments

Here is one idea:

Clear[sf, mySequence]

sf[x_] := If[x > 0, mySequence[8, 9], 0]

mySequence /: (h : Except[If])[x___, mySequence[y___], 
  z___] := h[x, y, z]

f[1, 2, sf[1], 4]

(* ==> f[1, 2, 8, 9, 4] *)

So I defined a sf function that returns the sequence as the result of an If statement. This is just an example, illustrating the general scenario that the result will be returned by some evaluation of the form returningHead[...,mySequence,...].

What gets returned is not a Sequence but instead an inert wrapper mySequence, which will be converted into a Sequence by the definition following mySequence /: - the only restriction being that I don't want it to be converted when it's in the last expression of my function, whose head was returningHead (specifically If in this example). In all other cases, mySequence will be converted to Sequence, as is illustrated by the last line.

Edit

The advantage of this wrapper approach combined with TagSetDelayed (the /: definition) is that you then have more fine-grained control over when mySequence gets delivered as a sequence. For example, you may be calling sf from inside a List as in the above example, but sometimes from inside a function f2 that can't deal with sequences. Then you can add f2 to the list in the Except statement to avoid errors in the processing of sf, until its output gets placed into the correct context.

share|improve this answer
    
Cool, that's a good idea. I'm just surprised it doesn't have a much simpler method built in. Thanks! :-) –  flarn2006 Feb 3 '13 at 7:32
    
Maybe there is a simpler method - you may want to wait before accepting this answer to give others some motivation to chime in... –  Jens Feb 3 '13 at 7:33
    
Okay, I unaccepted it. Sorry, but you did basically ask me to. Of course, if nobody else posts a simpler method I'll be sure to mark it as accepted again. –  flarn2006 Feb 3 '13 at 7:34
    
That's perfectly fine! –  Jens Feb 3 '13 at 7:35
    
I have sometimes needed that sort of control. Thanks for the edit. –  Michael E2 Feb 3 '13 at 18:36
add comment

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.