Можно ли автоматически лениво оценивать параметры функции в Mathematica? - PullRequest
4 голосов
/ 16 июля 2011

В Mathematica я хотел бы сделать что-то вроде:

f[Rational[a_, b_], Rational[c_, d_]] := {a+c, b+d}

Но если я оцениваю это с помощью выражений следующей формы, я получаю неправильный результат:

In: f[Rational[50, 100], Rational[4, 10]]
Out: {3, 7}
(* Expected: 54 / 110 ->  27 / 55 *)

Могу ли я заставить Mathematica немедленно прекратить упрощать выражение?Я могу просто удержать все, что я передаю, а затем заставить данную функцию просто вызвать ReleaseHold [..] для того, что было передано.

Это решение очень уродливо, и я нехочу сделать это.Я знаю, что некоторые функции в Mathematica автоматически удерживают все, что передано, и по той или иной причине откладывают его оценку, и я хотел бы сделать это здесь.

Короче говоря: как я могу заставить Mathematica ленивооценивать что-то, переданное в функцию, без необходимости удерживать ее вручную?

Ответы [ 2 ]

5 голосов
/ 16 июля 2011

В стандартной процедуре оценки каждый аргумент функции оценивается по очереди.Это можно предотвратить, установив атрибуты HoldFirst, HoldRest и HoldAll.Эти атрибуты заставляют Mathematica «хранить» конкретные аргументы в неоцененной форме.

http://reference.wolfram.com/legacy/v5/TheMathematicaBook/PrinciplesOfMathematica/EvaluationOfExpressions/2.6.5.html

например,

В документах говорится, что любые автоматически удерживаемые аргументы автоматически оцениваются при первом их использовании в теле функции.Однако, если по какой-то причине вы хотите продолжить работу с аргументом в форме Hold (например, если вы хотите выполнить сопоставление с образцом и переписать в неоцененной форме выражения), то, возможно, вы можете повторно Hold it.

1 голос
/ 16 июля 2011

Используя атрибут HoldAll, упомянутый ninjagecko, я смог найти решение.

На самом деле произошла другая проблема, которую я не смог сразу увидеть. В частности, моя функция не соответствовала шаблону, как я и думал.

Я думал, что моя первоначальная проблема заключалась в том, что Mathematica автоматически упрощала мои выражения, и мне нужно было лениво оценивать передаваемые параметры для правильного поведения.

На самом деле я забыл, что существует несколько способов представления выражений в Mathematica. В качестве примера игрушки рассмотрим следующую функцию, которая извлекает числитель и знаменатель дроби:

ExtractNumDem[Fraction[a_, b_]] := {a, b}
(* Already incorrect, ExtractNumDem[4 / 100] gives {1, 25} *)

Простое добавление атрибута HoldAll (или HoldFirst even) приводит к другой проблеме:

SetAttributess[ExtractNumDem, HoldAll];
ExtractNumDem[4 / 100] (* Gives ExtractNumDem[4 / 100] *)

Выражение 4 / 100 фактически равно Times[4, Power[100, -1]]. Чтобы исправить эту вторую проблему, мне пришлось добавить определение для дробей, которые выглядят так:

ExtractNumDem[Times[a_, Power[b_, -1]] := {a, b}
ExtractNumDem[4/100] (* Now gives {4, 100} *)

Мое решение для устранения проблемы в моем первоначальном ответе основывалось на том же самом принципе. Вот некоторый код, чтобы увидеть проблему, с которой я столкнулся:

ClearAll[ExtractNumDem]

ExtractNumDem[Rational[a_, b_]] := {a, b}
ExtractNumDem[4 / 100]

SetAttributes[ExtractNumDem, HoldAll];
ExtractNumDem[4 / 100]

ExtractNumDem[Times[a_, Power[b_, -1]]] := {a, b}
ExtractNumDem[4/100]
...