Функция Mathematica foo, которая может отличить foo [.2] от foo [.20]
-
06-07-2019 - |
Вопрос
Предположим, мне нужна функция, которая принимает число и возвращает его в виде строки в точности так, как она была задана. Следующее не работает:
SetAttributes[foo, HoldAllComplete];
foo[x_] := ToString[Unevaluated@x]
Вывод для foo [.2]
и foo [.20]
идентичен.
Причина, по которой я хочу это сделать, заключается в том, что мне нужна функция, которая может понимать даты с точками в качестве разделителей, например, f [2009.10.20]
. Я понимаю, что это странное злоупотребление Mathematica, но я делаю предметно-ориентированный язык и хочу использовать Mathematica в качестве парсера для него, просто выполняя eval (ToExpression). Я действительно могу сделать эту работу, если я могу полагаться на двузначные дни и месяцы, как 2009.01.02, но я хочу также разрешить 2009.1.2, и это в конечном итоге сводится к приведенному выше вопросу.
Я подозреваю, что единственный ответ - передать вещь в виде строки, а затем проанализировать ее, но, возможно, есть какой-то трюк, которого я не знаю. Обратите внимание, что это связано с этим вопросом: Mathematica: оценка без оценки, задержка, удержание, удержание, удержание, удержание, удержание, удержание, удержание, удержание, против и т. Д. И т. Д. р>
Решение
Я бы не стал полагаться на парсинг 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. Если вы можете получить выражение в виде строки, используйте UsingFrontEnd
в сочетании с ToExpression
:
UsingFrontEnd[ToExpression["foo[2009.09.20]", StandardForm]
РЕДАКТИРОВАТЬ 2: Есть много возможностей, если вы хотите поиграть с $ PreRead
, который позволяет применять специальную обработку для ввода, в виде строк , прежде чем они будут проанализированы. Р>
Другие советы
$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 более сложны, чем это должно быть ...
Floats, IIRC, разбиты Mathematica на настоящие Float, поэтому реального способа сделать то, что вы хотите, нет.