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.

I'm trying to build a head that recognizes molecules. Here's the code

Mol::arg = "Invalid molecule.";
Mol[Except[Subscript[_String, _Integer] ..]] := Message[Mol::arg]

I'd expect that this code should recognize molecules of the form

Mol[Subscript["C", 4], Subscript["N", 5]]

but it should issue the message if something like

Mol[Subscript["C", 4], 7]

is entered. However, when I enter this last one, no message is issued. I don't understand what I'm doing wrong.

share|improve this question

3 Answers 3

up vote 10 down vote accepted

To simplify the example, consider this:

f[Except[1 ..]] := "match"

{f[1], f[3], f[3, 5]}
{f[1], "match", f[3, 5]}

Except is a single argument, not a sequence. Therefore the definition cannot match when there are multiples arguments of f.


I think Rojo's answer is the cleanest method to get the behavior you want, but another is:

mol::arg = "Invalid molecule.";
pat = Subscript[_String, _Integer]

mol[x__] := With[{}, Message[mol::arg] /; ! MatchQ[{x}, {pat ..}]]

Or, using a trick Rojo showed me to prevent infinite recursion:

Module[{guard = True},
  x : mol[pat ..] /; guard := Block[{guard = False}, x];
      mol[__]     /; guard := Message[mol::arg]
]
share|improve this answer
    
@Rojo As you say, I just need a wrapper, so that when I pattern match something like _Mol, I can be sure that it is formatted in the correct way. –  becko May 20 '12 at 17:01
    
"Except is a single argument, not a sequence." ... So that explains why my code doesn't work. But then, is there some sort of SequenceExcept in Mathematica? –  becko May 20 '12 at 17:12
    
@becko not that I am aware of. I added a couple more method you could use to my answer. As it stands, my post is the only one that actually answers the question you asked, therefore IMHO you should either Accept it, or (as it seems you prefer) change your answer to move emphasis from why to how. –  Mr.Wizard May 20 '12 at 20:34
1  
@Rojo initial testing indicates Mol[___, Except[Subscript[_String, _Integer]], ___] is still several times faster, probably for this reason. –  Mr.Wizard May 21 '12 at 9:33
1  
@becko you're right, I misapplied Leonid's answer. What I mean is that both of the methods in my answer involve upper-level programming while Rojo's answer is pure pattern matching, even if it does use ___, and perhaps that is why it's faster. I am now well aware that Mathematica's pattern engine has performance issues, and I certainly don't mean to imply that pattern matching will be faster than top level programming. –  Mr.Wizard May 22 '12 at 12:32

I'd suggest

Mol[___, Except[Subscript[_String, _Integer]], ___]

I think it's an interesting question. I never dug into this but as far as I recall, I never saw Except working for pattern sequences

share|improve this answer
    
This also works. But I think it's slower than Heike's method. Just run ... –  becko May 20 '12 at 16:46
    
molecule=Sequence@@Table[Subscript[RandomChoice[{"C","N","S","H"}],RandomIntege‌​r[{1,500}]],{i,1,1000}] –  becko May 20 '12 at 16:47
    
and then this ... –  becko May 20 '12 at 16:47
    
{Timing[Mol1[molecule];], Timing[Mol2[molecule];]} –  becko May 20 '12 at 16:47
1  
@Becko, I get better timings for my version. Averaging 0.000146606 in Heike's and 0.0000437927 in mine, for your example –  Rojo May 20 '12 at 16:53

You could do something like this

Clear[Mol];
Mol::arg = "Invalid molecule.";
Mol[p__ /; MatchQ[{p}, Except[{Subscript[_String, _Integer] ..}]]] :=  Message[Mol::arg]
share|improve this answer
1  
cool. That works just like I wanted it. But what's wrong my code? And also, isn't the /; a little inefficient compared to other forms of pattern matching? (Not that I care for this particular application about efficiency) –  becko May 20 '12 at 16:28

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.