7
$\begingroup$

I am trying to write a function with a pattern that tests its arguments for a particular structure. But in that pattern I'd like to name a subpattern to make it easier to exract and operate on.

The code below works fine:

Plant[x:Allele[_,_]..] := Involute[{x}] 

But what I really want is to extract the parts of each Allele expression and pass them as lists to Involute. I tried using the definition below (expecting a and b to be Sequences of the arguments to Allele):

Plant[x:Allele[a_,b_]..] := Involute[{x}, {a}, {b}] 

Unfortunately, this produces unexpected results when evaluated - specifically it only seems to work on expressions that accept a single Allele argument. When a expand the pattern I get:

 In: (x:Allele[a_,b_]..)//FullForm Out: Pattern[x, Repeated[Allele[Pattern[a, Blank[]], Pattern[b, Blank[]]]]] 

which doesn't seem right. Where's the mistake?

$\endgroup$
3
  • $\begingroup$ Remember to use lowercase for your defined symbols $\endgroup$ Commented Jan 24, 2013 at 2:20
  • 3
    $\begingroup$ Unless you strongly believe it's a bug, the result isn't nonsensical, but just unexpected to you. It would be helpful to know what you are expecting $\endgroup$ Commented Jan 24, 2013 at 2:21
  • $\begingroup$ In any case, if it is the pattern expansion what doesn't seem right to you, you'll probably fix it with proper parentheses? $\endgroup$ Commented Jan 24, 2013 at 2:26

2 Answers 2

9
$\begingroup$

When you write a pattern like

Plant[x:Allele[a_,b_]..] := Involute[{x}, {a}, {b}] 

what you're telling Mathematica is (in words): "When you encounter a call to Plant with one or more arguments, all of which have the head Allele and all of which have the same two arguments, then replace with ...". If that's what you actually meant, then it works as expected. For instance:

Plant[Allele[x, y], Allele[x, y]] (* Involute[{Allele[x, y], Allele[x, y]}, {x}, {y}] *) 

My guess is that this is not what you meant, because this doesn't work when you have plants with different alleles. You probably want to do something like:

Involute[{args of Plant with head Alelle}, {first args to Allele}, {last args to Allele}] 

One way to achieve this would be:

Clear@Plant Plant[x : Allele[_, _] ..] := Involute[{x}, Sequence @@ Transpose[{x} /. Allele -> List]] 

which works as follows:

Plant[Allele[a, b], Allele[x, y]] (* Involute[{Allele[a, b], Allele[x, y]}, {a, x}, {b, y}] *) 
$\endgroup$
4
  • $\begingroup$ Indeed, I understand my mistake. I assumed that a_ and b_ just assigned a name to that portion of the expression, but they actually do more. They fix a value to that portion of the expression that then has to match in all subsequent arguments. It seems that MMA pattern matching isn't quite the same as expression destructuring techniques that one finds in languages like Lisp or Clojure. $\endgroup$ Commented Jan 24, 2013 at 3:21
  • $\begingroup$ @LBushkin even though rm clearly got your intentions, I insist it would be nice for you to make your question clearer. Your intentions should be understood from the question, for future visitors. Furthermore, I'm intrigued, what were you expecting a_ and b_ to represent? I have no List or Clojure background $\endgroup$ Commented Jan 24, 2013 at 3:27
  • $\begingroup$ @Rojo - I was expecting a_ and b_ to represent a Sequence of expressions derived by extracting them from the expression x. I will refine my question to make it a bit clearer. $\endgroup$ Commented Jan 24, 2013 at 3:29
  • $\begingroup$ @Rojo: This blog article gives some good examples of destructuring in Clojure. $\endgroup$ Commented Jan 24, 2013 at 3:33
8
$\begingroup$

Supplementing R.M's answer, here are a few other ways of getting what you may be after:

Plant[x : Allele[_, _] ..] := Involute[{x}, {x}[[All, 1]], {x}[[All, 2]]] Plant[x : Allele[_, _] ..] := Involute[{x}, ##] & @@ Thread[{x}, Allele] Plant[x : Allele[_, _] ..] := Thread[{x}, Allele] /. _[ab__] :> Involute[{x}, ab] 

Use:

Plant[Allele[i, x], Allele[j, y], Allele[k, z]] 
Involute[{Allele[i, x], Allele[j, y], Allele[k, z]}, {i, j, k}, {x, y, z}] 

Depending on what these functions do you may need Unevaluated, Hold, or a HoldAll attribute to prevent premature evaluation.

$\endgroup$
1
  • $\begingroup$ Thanks for the answer - I particularly like the [[All,_]] syntax to extract parts from the outer expression. I should have remembered that (I've seen it, but haven't used it much). $\endgroup$ Commented Jan 24, 2013 at 3:24

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.