Mathematica 函数 foo 可以区分 foo[.2] 和 foo[.20]

发布于 2024-08-08 13:30:16 字数 645 浏览 1 评论 0原文

假设我想要一个函数,它接受一个数字并将其作为字符串返回,与给定的完全相同。以下内容不起作用:

SetAttributes[foo, HoldAllComplete];
foo[x_] := ToString[Unevaluated@x]

foo[.2]foo[.20] 的输出是相同的。

我想要这样做的原因是我想要一个可以理解以点作为分隔符的日期的函数,例如,f[2009.10.20]。我意识到这是对 Mathematica 的奇怪滥用,但我正在制作一种特定于领域的语言,并希望通过执行 eval (ToExpression) 来使用 Mathematica 作为它的解析器。如果我可以依靠两位数的日期和月份(例如 2009.01.02),我实际上可以完成这项工作,但我也想允许 2009.1.2,这最终归结为上述问题。

我怀疑唯一的答案是将其作为字符串传递,然后解析它,但也许有一些我不知道的技巧。请注意,这与以下问题相关:Mathematica:未评估、延迟、保留、HoldForm、HoldAllComplete、等等

Suppose I want a function that takes a number and returns it as a string, exactly as it was given. The following doesn't work:

SetAttributes[foo, HoldAllComplete];
foo[x_] := ToString[Unevaluated@x]

The output for foo[.2] and foo[.20] is identical.

The reason I want to do this is that I want a function that can understand dates with dots as delimiters, eg, f[2009.10.20]. I realize that's a bizarre abuse of Mathematica but I'm making a domain-specific language and want to use Mathematica as the parser for it by just doing an eval (ToExpression). I can actually make this work if I can rely on double-digit days and months, like 2009.01.02 but I want to also allow 2009.1.2 and that ends up boiling down to the above question.

I suspect the only answer is to pass the thing in as a string and then parse it, but perhaps there's some trick I don't know. Note that this is related to this question: Mathematica: Unevaluated vs Defer vs Hold vs HoldForm vs HoldAllComplete vs etc etc

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

此生挚爱伱 2024-08-15 13:30:16

我不会依赖 Mathematica 的浮点解析。相反,我会在 MakeExpression 上为 foo 定义规则。这允许您在将输入解析为浮点数之前将其截取为框。这对规则应该是一个很好的起点,至少对于 StandardForm 来说:

MakeExpression[RowBox[{"foo", "[", dateString_, "]"}], StandardForm] :=
  With[{args = Sequence @@ Riffle[StringSplit[dateString, "."], ","]},
    MakeExpression[RowBox[{"foo", "[", "{", args, "}", "]"}], StandardForm]]

MakeExpression[RowBox[{"foo", "[", RowBox[{yearMonth_, day_}], "]"}], 
    StandardForm] :=
  With[{args = 
    Sequence @@ Riffle[Append[StringSplit[yearMonth, "."], day], ","]},
      MakeExpression[RowBox[{"foo", "[", "{", args, "}", "]"}], StandardForm]]

我需要第二条规则,因为如果您尝试将第二个小数位放入数字。

编辑:为了从内核中使用它,您需要使用前端,但这在版本 7 中通常非常简单。如果您可以将表达式作为字符串获取,请使用 UsingFrontEndToExpression 结合使用:

 UsingFrontEnd[ToExpression["foo[2009.09.20]", StandardForm]

编辑 2: 如果您想使用 $PreRead,有很多可能性,其中允许您在解析输入之前对输入进行特殊处理,作为字符串

I wouldn't rely on Mathematica's float-parsing. Instead I'd define rules on MakeExpression for foo. This allows you to intercept the input, as boxes, prior to it being parsed into floats. This pair of rules should be a good starting place, at least for StandardForm:

MakeExpression[RowBox[{"foo", "[", dateString_, "]"}], StandardForm] :=
  With[{args = Sequence @@ Riffle[StringSplit[dateString, "."], ","]},
    MakeExpression[RowBox[{"foo", "[", "{", args, "}", "]"}], StandardForm]]

MakeExpression[RowBox[{"foo", "[", RowBox[{yearMonth_, day_}], "]"}], 
    StandardForm] :=
  With[{args = 
    Sequence @@ Riffle[Append[StringSplit[yearMonth, "."], day], ","]},
      MakeExpression[RowBox[{"foo", "[", "{", args, "}", "]"}], StandardForm]]

I needed the second rule because the notebook interface will "helpfully" insert a space if you try to put a second decimal place in a number.

EDIT: In order to use this from the kernel, you'll need to use a front end, but that's often pretty easy in version 7. If you can get your expression as a string, use UsingFrontEnd in conjunction with ToExpression:

 UsingFrontEnd[ToExpression["foo[2009.09.20]", StandardForm]

EDIT 2: There's a lot of possibilities if you want to play with $PreRead, which allows you to apply special processing to the input, as strings, before they're parsed.

厌味 2024-08-15 13:30:16
$PreRead = If[$FrontEnd =!= Null, #1, 
StringReplace[#,x:NumberString /; StringMatchQ[x,"*.*0"] :>
     StringJoin[x, "`", ToString[
       StringLength[StringReplace[x, "-" -> ""]] - 
        Switch[StringTake[StringReplace[x, 
           "-" -> ""], 1], "0", 2, ".", 1, _, 
         1]]]]] & ; 

将把 foo[.20] 显示为 foo[0.20]。它的InputForm将是
foo[0.2`2.]

我发现在 Mathematica 中解析和显示数字格式比
应该是...

$PreRead = If[$FrontEnd =!= Null, #1, 
StringReplace[#,x:NumberString /; StringMatchQ[x,"*.*0"] :>
     StringJoin[x, "`", ToString[
       StringLength[StringReplace[x, "-" -> ""]] - 
        Switch[StringTake[StringReplace[x, 
           "-" -> ""], 1], "0", 2, ".", 1, _, 
         1]]]]] & ; 

will display foo[.20] as foo[0.20]. The InputForm of it will be
foo[0.2`2.]

I find parsing and displaying number formats in Mathematica more difficult than
it should be...

纸伞微斜 2024-08-15 13:30:16

IIRC 浮点数由 Mathematica 解析为实际的浮点数,因此没有真正的方法可以做你想做的事情。

Floats are, IIRC, parsed by Mathematica into actual Floats, so there's no real way to do what you want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文