1
$\begingroup$

I'm kinda stuck here, and I could really use some help:

I want to define a function, let's call it quarterValue, that accepts a Rule as an input and returns an appropriate expression as output.

A template expression (a type of sorts?) of what the input is expected to be, is given below:

StringExpression["Q", DigitCharacter] -> _?NumericQ 

and as far as the output is concerned, I was going to give three different quarterValue definitions in order to account for the different possible input configurations (presented here from the most specific to the least specific), namely

ClearAll[quarterValue]
quarterValue::err = "Error: `1`->`2`: `3`";

(* catch missing values *)
quarterValue[(q:StringExpression["Q", DigitCharacter]) -> ""] := q -> Missing[]

(* regular input *)
quarterValue[(q:StringExpression["Q", DigitCharacter]) -> (nmc_?NumericQ)] := q -> nmc

(* account for irregular input etc *)
(* emit a Message and return the input unevaluated *)
quarterValue[e:((q:StringExpression["Q", DigitCharacter]) -> x_)] := (
  Message[quarterValue::err, q, x, e];
  e
 )

I thought I was smart enough but the Kernel had other plans.

I was anticipating that

quarterValue[StringExpression["Q", DigitCharacter] -> (whatever_)] 

would match against input values, because StringMatchQ["Qi", StringExpression["Q", DigitCharacter]], where i is any value from {1,2,3,4}, matches every possible lhs of the input Rule and either "" or _?NumericQ or _ match the rhs of the input Rule.

It seems that, this is not the case.

How can I mix string and regular patterns in order to make the SetDelayed definition of quarterValue evaluate correctly?

$\endgroup$
2
  • $\begingroup$ Similar: 8945 $\endgroup$
    – WReach
    Mar 27, 2022 at 2:16
  • $\begingroup$ Although StringMatchQ["Q1", StringExpression["Q", DigitCharacter]] matches, StringMatchQ[StringExpression["Q", DigitCharacter], StringExpression["Q", DigitCharacter]] does not match because StringMatchQ[StringExpression["Q", DigitCharacter] is not a string, but a string expression containing a symbolic string. $\endgroup$ Mar 27, 2022 at 18:37

1 Answer 1

0
$\begingroup$

Ok, I found a way to make it work, but I still don't get why my original code didn't work as expected.

The solution I figured out is to check for the quarter string pattern using a pattern test:

ClearAll[quarterValue]

quarterValue::err = "Error: `1`->`2`: `3`";

(*catch missing values*)
quarterValue[q_ -> ""] /; StringMatchQ[q, StringExpression["Q", DigitCharacter]] :=  q -> Missing[]

(*regular input*)
quarterValue[q_ -> (nmc_?NumericQ)] /; StringMatchQ[q, StringExpression["Q", DigitCharacter]] := q -> nmc

(*account for irregular input etc*)
(*emit a Message and return the input unevaluated*)
quarterValue[e : (q_ -> x_)] /; StringMatchQ[q, StringExpression["Q", DigitCharacter]] := (
  Message[quarterValue::err, q, x, e];
  e
 )

This way all the following expressions evaluate as expected:

quarterValue["Q1" -> ""]
(* "Q1" -> Missing[] *)

quarterValue["Q3" -> 12.120]
(* "Q3" -> 12.12 *)

quarterValue["Q2" -> "x"]
(* quarterValue: Error. x should be NumericQ or \"\" *)
(* "Q2" -> "x" *) 
$\endgroup$
1
  • $\begingroup$ Simply put: you can only use string patterns inside special functions like StringMatchQ. I would also recommend using quarterValue[q_String -> ""] /; StringMatchQ[q,...] instead because otherwise StringMatchQ can start spilling messages when q is not a string. $\endgroup$ Aug 18, 2023 at 14:07

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.