UPDATE
Самую последнюю версию функции shortInputForm
можно найти здесь .
Оригинальный пост
Вот еще одно, еще лучшее решение (совместимо с Mathematica 5):
myInputForm[expr_] :=
Block[{oldContexts, output, interpretation, skeleton},
output = ToString[expr, InputForm];
oldContexts = {$Context, $ContextPath};
$Context = "myTemp`"; $ContextPath = {$Context};
output = DisplayForm@ToBoxes[ToExpression[output] /.
{myTemp`interpretation -> If[$VersionNumber >= 6,
System`Interpretation, System`First@{#} &],
myTemp`Row -> System`Row,
myTemp`skeleton -> System`Skeleton,
myTemp`sequence :> (System`Sequence @@ # &)}, StandardForm];
{$Context, $ContextPath} = oldContexts; output]
shortInputForm[expr_] := myInputForm[expr /. {{} -> Sequence[],
lst : {x_ /; VectorQ[x, NumberQ], y__} /;
(MatrixQ[lst, NumberQ] && Length[lst] > 3) :>
{x /. v : {a_, b__} /; Length[v] > 3 :>
{a, interpretation[skeleton[Length[{b}]], sequence@{b}]},
interpretation[skeleton[Length[{y}]], sequence@{y}]},
lst : {x_, y__} /; VectorQ[lst, NumberQ] && Length[lst] > 3 :>
{x, interpretation[skeleton[Length[{y}]], sequence@{y}]}}]
Как это работает
Это решение основано на простой идее: нам нужно заблокировать преобразование таких вещей, как Graphics
, Point
и других в набранные выражения , чтобы они отображались во внутренней форме (как выражения, подходящие для ввода). К счастью, если мы сделаем это, результирующий вывод StandardForm
окажется просто отформатированным (двумерным) InputForm
исходного выражения. Это как раз то, что нужно!
Но как это сделать?
Прежде всего, это преобразование выполняется с помощью FormatValues
, определенного для Symbol
s, например Graphics
, Point
и т. Д. Полный список таких Symbol
s можно получить, оценивая следующее:
list = Symbol /@
Select[DeleteCases[Names["*"], "I" | "Infinity"],
ToExpression[#, InputForm,
Function[symbol, Length[FormatValues@symbol] > 0, HoldAll]] &]
Моей первой идеей было просто Block
все эти Symbol
с (и это работает!):
myInputForm[expr_] :=
With[{list = list}, Block[list, RawBoxes@MakeBoxes@expr]]
Но этот метод приводит к оценке всех этих Symbol
с, а также оценивает все FormatValues
для всех Symbol
с в $ContextPath
. Я думаю, что этого следует избегать.
Другой способ заблокировать эти FormatValues
- просто удалить контекст "System`"
из $ContextPath
. Но это работает, только если эти Symbol
еще не разрешены в контексте "System`"
. Поэтому нам нужно сначала преобразовать наше выражение в String
, затем удалить контекст "System`"
из $ContextPath
и, наконец, преобразовать строку обратно в исходное выражение. Тогда все новые Symbol
будут связаны с текущими $Context
(и Graphics
, Point
и т. Д. - тоже, поскольку их нет в $ContextPath
). Для предотвращения конфликтов затенения контекста и засорения контекста "Global`"
я переключаю $Context
на "myTemp`"
, который может быть легко очищен при необходимости.
Вот как myInputForm
работает.
Теперь о shortInputForm
. Идея состоит не только в том, чтобы отобразить сокращенную версию myInputForm
, но и в том, чтобы сохранить возможность выбирать и копировать части сокращенного кода в новую входную ячейку и использовать этот код, поскольку он будет полным кодом без сокращений. В версии 6 и выше можно достичь последнего с Interpretation
. Для совместимости с до-6 версиями Mathematica
я добавил фрагмент кода, который удаляет эту способность, если $VersionNumber
меньше 6.
Единственная проблема, с которой я столкнулся при работе с Interpretation
, заключается в том, что у него нет атрибута SequenceHold
, поэтому мы не можем просто указать Sequence
в качестве второго аргумента для Interpretation
. Но этой проблемы легко избежать, добавив последовательность в List
и затем Apply
ing Sequence
к ней:
System`Sequence @@ # &
Обратите внимание, что мне нужно указать точный контекст для всех встроенных Symbol
s, которые я использую, потому что в момент их вызова контекст "System`"
отсутствует в $ContextPath
.
На этом заканчиваются нестандартные решения, принятые мной при разработке этих функций. Предложения и комментарии приветствуются!