15
$\begingroup$

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.

$\endgroup$

3 Answers 3

10
$\begingroup$

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]
]
$\endgroup$
11
  • $\begingroup$ @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. $\endgroup$
    – a06e
    Commented May 20, 2012 at 17:01
  • $\begingroup$ "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? $\endgroup$
    – a06e
    Commented May 20, 2012 at 17:12
  • $\begingroup$ @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. $\endgroup$
    – Mr.Wizard
    Commented May 20, 2012 at 20:34
  • 1
    $\begingroup$ @Rojo initial testing indicates Mol[___, Except[Subscript[_String, _Integer]], ___] is still several times faster, probably for this reason. $\endgroup$
    – Mr.Wizard
    Commented May 21, 2012 at 9:33
  • 1
    $\begingroup$ @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. $\endgroup$
    – Mr.Wizard
    Commented May 22, 2012 at 12:32
13
$\begingroup$

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

$\endgroup$
6
  • $\begingroup$ This also works. But I think it's slower than Heike's method. Just run ... $\endgroup$
    – a06e
    Commented May 20, 2012 at 16:46
  • $\begingroup$ molecule=Sequence@@Table[Subscript[RandomChoice[{"C","N","S","H"}],RandomInteger[{1,500}]],{i,1,1000}] $\endgroup$
    – a06e
    Commented May 20, 2012 at 16:47
  • $\begingroup$ and then this ... $\endgroup$
    – a06e
    Commented May 20, 2012 at 16:47
  • $\begingroup$ {Timing[Mol1[molecule];], Timing[Mol2[molecule];]} $\endgroup$
    – a06e
    Commented May 20, 2012 at 16:47
  • 1
    $\begingroup$ @Becko, I get better timings for my version. Averaging 0.000146606 in Heike's and 0.0000437927 in mine, for your example $\endgroup$
    – Rojo
    Commented May 20, 2012 at 16:53
9
$\begingroup$

You could do something like this

Clear[Mol];
Mol::arg = "Invalid molecule.";
Mol[p__ /; MatchQ[{p}, Except[{Subscript[_String, _Integer] ..}]]] :=  Message[Mol::arg]
$\endgroup$
1
  • 1
    $\begingroup$ 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) $\endgroup$
    – a06e
    Commented May 20, 2012 at 16:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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