1

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?

joka
  • 332
  • 2
  • 12
  • 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. – Daniel Huber Mar 27 '22 at 18:37

1 Answers1

0

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" *)

joka
  • 332
  • 2
  • 12
  • 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. – Sjoerd Smit Aug 18 '23 at 14:07