В чем разница между Set (=) и SetDelayed (: =)?

Это обсуждение появилось в предыдущем вопросе, и мне интересно узнать разницу между ними. Иллюстрация с примером будет приятной.

Ответ 1

Основной пример

Вот пример из книги Леонида Шифрина Математическое программирование: расширенное введение

Это отличный ресурс для такого рода вопросов. Смотрите: (1) (2)

ClearAll[a, b]

a = RandomInteger[{1, 10}];

b := RandomInteger[{1, 10}]
Table[a, {5}]
  {4, 4, 4, 4, 4}
Table[b, {5}]
  {10, 5, 2, 1, 3}

Сложный пример

В приведенном выше примере может показаться, что после создания определения для символа с помощью Set его значение фиксировано и не изменяется. Это не так.

f = ... присваивает f выражение, которое оно оценивает во время присвоения. Если символы остаются в этом оцениваемом выражении, а затем их значения изменяются, то и видимое значение f.

ClearAll[f, x]

f = 2 x;
f
  2 x
x = 7;
f
  14
x = 3;
f
  6

Полезно иметь в виду, как правила хранятся внутри страны. Для символов, которым присвоено значение symbol = expression, правила сохраняются в OwnValues. Обычно (но не всегда), OwnValues содержит только одно правило. В этом конкретном случае

In[84]:= OwnValues[f]

Out[84]= {HoldPattern[f] :> 2 x}

Важной для нас сейчас является r.h.s., которая содержит x как символ. Что действительно важно для оценки, эта форма - способ сохранения правил внутри страны. Пока x не имеет значения в момент назначения, оба Set и SetDelayed производят (создают) то же правило выше в глобальной базе правил, и это все, что имеет значение. Таким образом, они эквивалентны в этом контексте.

Конечным результатом является символ f, который имеет функциональноподобное поведение, поскольку его вычисленное значение зависит от текущего значения x. Однако это не истинная функция, поскольку она не имеет никаких параметров и вызывает только изменения символа x. Как правило, использование таких конструкций должно быть обескуражено, так как неявные зависимости от глобальных символов (переменных) столь же плохи в Mathematica, как и на других языках, - они делают код более сложным для понимания, а ошибки более тонкими и легче упускать из виду. Некоторое смежное обсуждение можно найти здесь.


Набор, используемый для функций

Set может использоваться для функций, и иногда это должно быть. Позвольте привести пример. Здесь Mathematica символически решает Sum, а затем присваивает это aF (x), которое затем используется для графика.

ClearAll[aF, x]

aF[x_] = Sum[x^n Fibonacci[n], {n, 1, \[Infinity]}];

DiscretePlot[aF[x], {x, 1, 50}]

enter image description here

Если, с другой стороны, вы пытаетесь использовать SetDelayed, тогда вы передаете каждое значение, которое будет отображаться в функции Sum. Мало того, что это будет намного медленнее, но, по крайней мере, на Mathematica 7, он терпит неудачу.

ClearAll[aF, x]

aF[x_] := Sum[x^n Fibonacci[n], {n, 1, \[Infinity]}];

DiscretePlot[aF[x], {x, 1, 50}]

Если вы хотите убедиться, что возможные глобальные значения формальных параметров (x здесь) не мешают и игнорируются в процессе определения новой функции, альтернативой Clear является обертка Block вокруг определение:

ClearAll[aF, x];
x = 1;
Block[{x}, aF[x_] = Sum[x^n Fibonacci[n], {n, 1, \[Infinity]}]];

Взгляд на определение функции подтверждает, что мы получаем то, что хотели:

?aF
Global`aF
aF[x_]=-(x/(-1+x+x^2))

Ответ 2

In[1]:= Attributes[Set]

Out[1]= {HoldFirst, Protected, SequenceHold}

In[2]:= Attributes[SetDelayed]

Out[2]= {HoldAll, Protected, SequenceHold}

Как вы можете видеть по их атрибутам, обе функции имеют свой первый аргумент (символ, которому вы назначаете), но они отличаются тем, что SetDelayed также содержит второй аргумент, а Set - нет. Это означает, что Set будет оценивать выражение справа от = во время создания задания. SetDelayed не оценивает выражение справа от :=, пока фактически не будет использована переменная.

Что происходит более ясно, если правая сторона задания имеет побочный эффект (например, Print []):

In[3]:= x = (Print["right hand side of Set"]; 3)
x
x
x

During evaluation of In[3]:= right hand side of Set

Out[3]= 3

Out[4]= 3

Out[5]= 3

Out[6]= 3

In[7]:= x := (Print["right hand side of SetDelayed"]; 3)
x
x
x

During evaluation of In[7]:= right hand side of SetDelayed

Out[8]= 3

During evaluation of In[7]:= right hand side of SetDelayed

Out[9]= 3

During evaluation of In[7]:= right hand side of SetDelayed

Out[10]= 3

Ответ 3

:= предназначен для определения функций, а = - для установки значения в основном.

т.е. := будет оценивать, когда его чтение, = будет оцениваться, когда оно установлено.

подумайте:

x = 2
y = x
z := x
x = 4

Теперь z равно 4, если оценивается, а y еще 2