Message Boards Message Boards

0
|
348 Views
|
9 Replies
|
8 Total Likes
View groups...
Share
Share this post:

Constraints on patterns with a pure function with two parameters

Posted 7 days ago

This question arised after reading the almost-last example appearing in the technote on Patterns, in section Putting Constraints on Patterns.

Why the following function doesn't work?

q[x_Integer, y_Integer?(Function[{v, u}, v + u < 8])] := qp[x + y]

That is, I want the function q to be evaluated only if x+y<8, by using a pure function, so that, for example,

{q[{3, 4}], q[{1, 1}], q[{-5, -7}]}

would return

(*{qp[7],qp[2],q[{-5,-7}]}*)

Note that the following works:

q[{x_Integer, y_Integer}?(Function[v, v[[1]] + v[[2]] < 8])] :=  qp[x + y]

But I want the function q to accept two separate arguments x and y, and not a list of two arguments {x,y}.

POSTED BY: Ehud Behar
9 Replies
Posted 7 days ago

Can you think of a way that does make use of a pure function to restrict two arguments as I tried?

I'm not sure what you think would qualify. I'm kind of confused by the question. I didn't really think any of this was about pure functions. The way argument checking works is that the test in the pattern test is applied whenever the arguments match the specific pattern that the test is attached to. To match more than one argument, you'd need a pattern that matches more than one argument. The way to do that is with BlankSequence or BlankNullSequence. But even then, the test will be applied to each element of the matching sequence. That's by design. The common case is checking that all arguments satisfy some common constraint. So, I guess I'm saying "no", I don't know how to do what you're asking in the way that I understand what you're asking. But I may not understand what you're asking.

do you think that this is one of the reasons the WL developers decided to give the users multiple syntaxes to choose from to match patterns?

Well, first off, I don't have insight into WL developers motivations. But setting that aside, I don't think this question makes much sense. In the course of developing the language they encountered a need for various kinds of tests and constraints and pattern matching techniques. And so, they came up with language features to handle those situations. I don't really think your specific example illustrates an important situation that they had to deal with. I think you're just expecting things to work one way and they just don't work that way. Or maybe the answer is "yes", because there is a way to solve your particular problem, and so I guess that illustrates the need for a variety of techniques for checking things. But you seem to be implying that the alternate technique is somehow deficient. I don't understand why.

Having said all of that, there very well might be a way to achieve something closer to what you expect. I will guess that if it does exist, it will be ugly.

POSTED BY: Eric Rimbey
Posted 7 days ago

I assume you are referring to this example:

q[{x_Integer, y_Integer}?(Function[v, v . v > 4])] := qp[x + y]

You need to pay attention to where the parentheses/brackets are. In the above example the ? (PatternTest) is applied to the List ({}). So, in the Function, the argument v will be a pair. To emphasize, it won't be two arguments, but a list of length 2.

Now let's look at your attempt:

q[x_Integer, y_Integer?(Function[{v, u}, v + u < 8])] := qp[x + y]

In this case, the PatternTest is applied to the argument named y. But the function you've provided for that test takes two arguments. The syntax may seem weird, but it needs to be that way to avoid ambiguity in the arguments to Function. So, no matter what you supply as the y argument, the PatternTest will fail.

To create a constraint on two arguments, you need to put that constraint at a wider scope. You could do something like this:

q[x_Integer, y_Integer] := qp[x + y] /; x + y < 8
POSTED BY: Eric Rimbey
Posted 7 days ago

Thanks very much! Your reply helps a lot.

Can you think of a way that does make use of a pure function to restrict two arguments as I tried?

If the answer is that it is not possible, and I have to resort to your suggestion (/; at the end), then do you think that this is one of the reasons the WL developers decided to give the users multiple syntaxes to choose from to match patterns?

POSTED BY: Ehud Behar

I wonder why this works as I would expect:

Remove[q];
q[x_?(Function[True])] := x
q[1]

while this triggers infinite recursion:

Remove[q];
(q[x_])?(Function[True]) := x
q[1]
POSTED BY: Gianluca Gorni
Posted 6 days ago

In

(q[x_])?(Function[True]) := x

before we can determine whether to apply the definition to the input, we must evaluate the input to see if it satisfies the pattern test. To evaluate the input, we must decide whether to apply the definition, which we do by checking the pattern test. To check the pattern test, we must evaluate the input. To evaluate the input, we must decide whether to apply the definition, which we do by checking the pattern test. To check the pattern test, we must evaluate the input. To evaluate the input, we must decide whether to apply the definition, which we do by checking the pattern test. To check the pattern test, we must evaluate the input. To evaluate the input, we must decide whether to apply the definition, which we do by checking the pattern test. To check the pattern test, we must evaluate the input.

POSTED BY: Eric Rimbey

With pattern Condition we don't get infinite recursion:

Remove[q]
q[x_] /; True := x
q[1]

I am confused.

POSTED BY: Gianluca Gorni
Posted 6 days ago

The condition can be evaluated without reference to any specific sub-expression. When using PatternTest, the pattern it's attached to will have matched some value (some argument, say) and that value gets passed to the test function. When using Condition, the test isn't a function waiting for input but a complete expression that gets evaluated. That expression might depend on other symbols with values bound at the time of evaluation, but any recursion you get would be caused by recursive definitions of those symbols, not on the mechanics of evaluating the Condition test.

POSTED BY: Eric Rimbey

First, function definitions have the form pattern := value. We will refer to pattern below.

This shows what happens in a reasonable amount of output:

Remove[q];
(q[x_])?(Function[True]) := x;
Block[{$RecursionLimit = 20},
 q[1] // TracePrint]

The pattern has the form pat ? test. When pat ? text is evaluated, test[match] is evaluated, where match is the expression matching pat. In your definition pat is q[x_] and test is your Function; the match is q[1].

What to look for in the output is that when q[1] is to be evaluated, the expression Function[True][q[1]] is evaluated (or in standard form (True&)[q[1]]). When this is evaluated, it first tries to evaluate q[1], and you enter into infinite recursion.

For the definition q[x_] /; True := x, the pattern has the form pat /; test. In pat /; test, test is first evaluated, and pat is involved only to the extent that it or parts of it appear in test. You would get infinite recursion if the complete function call appears in test. Hard to imagine a reasonable use-case (obviously), but here's a definition that results in infinite recursion:

ClearAll[q];
call : q[x_] /; TrueQ[call] || True := x;

This does not have the recursion problem:

ClearAll[q];
call : q[x_] /; True || TrueQ[call] := x;
POSTED BY: Michael Rogers

Thank you, this was very interesting.

POSTED BY: Gianluca Gorni
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract