Возвращает равенство из функции Mathematica

У меня есть функция, которая возвращает равенства, которые я хочу напечатать, например, x==y или 2x+5==10. Обычно это не имеет значения для математики, она не может ее еще больше упростить.

Однако иногда обе стороны равны, но я хочу иметь возможность печатать равенство в невычисленном виде: то есть я хочу, чтобы Mathematica печатала x==x, а не True.

Очень простой пример:

Print[printableEqual[x,y]]

должен печатать x==y, а

Print[printableEqual[x,x]]

должен напечатать x==x

Изменить: причина в том, что у меня есть связь между графиками. Я хотел бы вернуть такие вещи, как

G1 == t*G2 + s*G3

где t,s — целые числа, а Gi — графические объекты в системе Mathematica. Простое возвращение этого отлично работает (поскольку Mathematica не может упростить такие вещи), ЗА ИСКЛЮЧЕНИЕМ G1 == G1, которое будет True.

Проблема в том, что использование Defer или HoldForm дает

Private`lhs$714 == Private`rhs$714

в качестве вывода, то есть частные переменные в моем пакете не оцениваются как моя графика.


person Per Alexandersson    schedule 31.01.2011    source источник
comment
Как насчет printableEqual[x_,y_]:=Row[{x," \\[LongEqual] ",y}]?   -  person Simon    schedule 01.02.2011


Ответы (4)


Для этого можно использовать Defer:

In[5]:= printableEqual[x_, y_] := Defer[x == y];
In[6]:= printableEqual[1, 2]
Out[6]= 1 == 2
person Sebastian Paaske Tørholm    schedule 31.01.2011
comment
Не работает, если printableEqual находится в пакете, см. мое редактирование. - person Per Alexandersson; 01.02.2011

Другой трюк — просто использовать Unevaluated:

In[1] := Print[Unevaluated[1 == 1]]
1==1
person Michael Pilat    schedule 31.01.2011
comment
@Michael Не могли бы вы прояснить разницу между использованием Defer и Unevaluated здесь? - person Dr. belisarius; 31.01.2011
comment
Unevaluated ничего не оборачивает вокруг выражения. Defer[expr] — это оболочка, которая при печати или выводе отображается как неоцененная форма expr, но при повторном использовании в качестве ввода действует как оцененная форма expr. Unevaluated просто предотвращает оценку один раз, если хотите. Иными словами, Head[Unevaluated[1==1]] это Equals, а Head[Defer[1==1]] это Defer. - person Michael Pilat; 01.02.2011
comment
На самом деле, я думаю, что Unevaluated действительно оборачивает выражение - просто обёртка прозрачна для большинства функций. Сравните {FullForm[Defer[1 + 1]],FullForm[Unevaluated[1 + 1]]} и {Head[Defer[1 + 1]], Head[Unevaluated[1 + 1]]}. Также см. ответ @Leonid здесь. - person Simon; 01.02.2011
comment
Unevaluated заворачивается, но удаляется, поэтому его невидимость является следствием процесса оценки. Если завернуть в несколько слоев Unevaluated, останутся внутренние, например Head[Unevaluated[Unevaluated[Print["*"]]]]. Проблема с Unevaluated заключается в том, что вы никогда не знаете, сколько раз вам нужно вложить его и сколько из них будет удалено — это зависит от конкретной оценки, также может зависеть от данных, поэтому это не надежный способ предотвращения оценка выражения, за исключением случаев, когда мы делаем это один раз и нуждаемся в этом один раз. - person Leonid Shifrin; 01.02.2011
comment
@Simon: ваш пример FullForm[Unevaluated[1 + 1]] - особый случай. На самом деле происходит то, что этот Unevaluated действительно удаляется в процессе оценки. Но, поскольку окружающих функций нет (а FullForm на самом деле не является окружающей функцией в том смысле, как она работает), результатом будет Plus[1,1] (не оценивается). В таких случаях (когда не были найдены применимые правила для частей, где Unevaluated был зачищен), восстанавливается Unevaluated, что вы и наблюдали. Очень похожий пример приводил в своей книге Дэвид Вагнер — отсюда я и узнал об этом. - person Leonid Shifrin; 01.02.2011
comment
@Леонид: Спасибо за разъяснение. - person Simon; 01.02.2011
comment
Извините за путаницу, я должен был сказать, что Unevaluated не приводит к постоянной обертке вокруг выражения. - person Michael Pilat; 01.02.2011
comment
@Michael: ваша формулировка постоянной оболочки, вероятно, лучший краткий способ выразить это, который я видел - хороший образ, который нужно иметь в виду, спасибо. - person Leonid Shifrin; 01.02.2011

Обычно для такого рода вещей используется HoldForm. HoldForm — это заголовок, который работает так же, как Hold, в том смысле, что он не оценивает свое содержимое, но не отображается при печати в качестве вывода, например:

In[1]:= HoldForm[x == 3]
Out[1]= x == 3

In[2]:= HoldForm[x == x]
Out[2]= x == x

Как и в случае с Hold, вы можете интерполировать вещи в HoldForm, используя With или замену аргумента функции, например:

In[3]:= PrintableEqual[x_, y_] := HoldForm[x == y]

In[4]:= PrintableEqual[x, x]
Out[4]= x == x

Однако это будет означать, что аргументы оцениваются перед заменой, например:

In[5]:= PrintableEqual[x + x, 2 x]
Out[5]= 2 x == 2x

Если вы не хотите, чтобы это произошло, вы можете использовать SetAttributes и HoldAll:

In[6]:= SetAttributes[PrintableEqual, {HoldAll}]

In[7]:= PrintableEqual[x + x, 2 x]
Out[7]= x + x == 2 x

Обратите внимание, что HoldForm присутствует всегда, просто не отображается в выходной форме:

In[8]:= PrintableEqual[x, x] // InputForm
Out[8]= HoldForm[x == x]

Если вы хотите оценить вещи, используйте ReleaseHold:

In[9]:= ReleaseHold@PrintableEqual[x, x]
Out[9]= True
person Pillsy    schedule 31.01.2011

Еще одна вещь, которую вы можете сделать, это использовать Grid[] для выравнивания всех ваших равенств. Дополнительным преимуществом является то, что, поскольку вы на самом деле не создаете выражения с помощью Equal[], вам не нужно предотвращать их вычисление.

In[1]:= Grid[Table[{LHS[i],"\[LongEqual]",RHS[i]},{i,2}],
             Alignment -> {Right,Center,Left}]
Out[1]= LHS[1] == RHS[1]
        LHS[2] == RHS[2]

В том же духе вы можете вручную набирать текст, используя

printableEqual[LHS_, RHS_] := Row[{LHS, " \[LongEqual] ", RHS}]

или в более общем смысле

printableEqual[LHS_, mid___, RHS_] := Row[Riffle[{LHS, mid, RHS}, " \[LongEqual] "]]

Кстати, вывод из printableEqual[], определенного выше, можно преобразовать обратно в реальное выражение, используя ToExpression[ToString[#]]& или что-то вроде этого.

toRealEqual[Row[lst_List]] := Equal@@lst[[1;;-1;;2]] /; OddQ[Length[lst]] && Union[lst[[2;;-2;;2]]] == {" \[LongEqual] "}
person Simon    schedule 31.01.2011