Хранить неисследованную функцию в математике списка

Пример:

list:={ Plus[1,1], Times[2,3] }

Когда вы смотрите list, я получаю

{2,6}

Я хочу, чтобы они не были оценены (как указано выше), чтобы list возвращал

{ Plus[1,1], Times[2,3] }

Позже я хочу оценить функции в последовательности списка, чтобы получить

{2,6}

Количество неоцененных функций в list не известно заранее. Помимо Plus, определенные пользователем функции, такие как f[x_], могут храниться в list

Надеюсь, что этот пример ясен.

Каков наилучший способ сделать это?

Ответ 1

Лучший способ - сохранить их в Hold, а не List, например:

In[255]:= f[x_] := x^2;
lh = Hold[Plus[1, 1], Times[2, 3], f[2]]

Out[256]= Hold[1 + 1, 2 3, f[2]]

Таким образом, у вас есть полный контроль над ними. В какой-то момент вы можете вызвать ReleaseHold для их оценки:

In[258]:= [email protected]

Out[258]= Sequence[2, 6, 4]

Если вы хотите получить результаты в списке, а не Sequence, вместо этого вы можете использовать только [email protected]@lh. Если вам нужно оценить конкретный, просто используйте Part, чтобы извлечь его:

In[261]:= lh[[2]]

Out[261]= 6

Если вы настаиваете на своей конструкции, вот путь:

In[263]:= l:={Plus[1,1],Times[2,3],f[2]};
Hold[l]/.OwnValues[l]

Out[264]= Hold[{1+1,2 3,f[2]}]

ИЗМЕНИТЬ

Если у вас есть некоторые функции/символы с UpValues, которые могут оцениваться даже внутри Hold, вы можете использовать HoldComplete вместо Hold.

EDIT2

Как указал @Mr.Wizard в другом ответе, иногда вам может быть удобнее иметь Hold, обернутую вокруг отдельных элементов в вашей последовательности. Мой комментарий здесь заключается в том, что полезность обеих форм усиливается, когда мы понимаем, что очень легко превратить одно в другое и обратно. Следующая функция разделит последовательность внутри Hold на список удерживаемых элементов:

splitHeldSequence[Hold[seq___], f_: Hold] := List @@ Map[f, Hold[seq]]

например,

In[274]:= splitHeldSequence[Hold[1 + 1, 2 + 2]]

Out[274]= {Hold[1 + 1], Hold[2 + 2]}

объединение их обратно в один Hold еще проще - просто Apply Join:

In[275]:= Join @@ {Hold[1 + 1], Hold[2 + 2]}

Out[275]= Hold[1 + 1, 2 + 2]

Две различные формы полезны в разных обстоятельствах. Вы можете легко использовать такие вещи, как Union, Select, Cases в списке удерживаемых элементов, не задумываясь над оценкой. Как только вы закончите, вы можете объединить их обратно в один Hold, например, для подачи как неоцененной последовательности аргументов некоторой функции.

РЕДАКТИРОВАТЬ 3

По запросу @ndroock1, здесь приведен конкретный пример. Настройка:

l = {1, 1, 1, 2, 4, 8, 3, 9, 27} 
S[n_] := Module[{}, l[[n]] = l[[n]] + 1; l] 
Z[n_] := Module[{}, l[[n]] = 0; l]

размещение функций в Hold:

In[43]:= held = Hold[Z[1], S[1]]

Out[43]= Hold[Z[1], S[1]]

Вот как выглядит функция exec:

exec[n_] := MapAt[Evaluate, held, n]

Теперь

In[46]:= {exec[1], exec[2]}

Out[46]= {Hold[{0, 1, 1, 2, 4, 8, 3, 9, 27}, S[1]],  Hold[Z[1], {1, 1, 1, 2, 4, 8, 3, 9, 27}]}

Обратите внимание, что исходная переменная held остается неизменной, так как мы работаем над копией. Также обратите внимание, что исходная настройка содержит изменяемое состояние (l), которое не очень идиоматично в Mathematica. В частности, имеет смысл порядок оценок:

In[61]:= Reverse[{exec[2], exec[1]}]

Out[61]= {Hold[{0, 1, 1, 2, 4, 8, 3, 9, 27}, S[1]],  Hold[Z[1], {2, 1, 1, 2, 4, 8, 3, 9, 27}]}

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

Альтернативный способ хранения функций, предлагаемых @Mr.Wizard, может быть достигнут, например. как

В [63]: = listOfHeld = splitHeldSequence [проведено]

Out [63] = {Удерживать [Z 1], Удерживать [S 1]}

и здесь

In[64]:= execAlt[n_] := MapAt[ReleaseHold, listOfHeld, n]

In[70]:= l = {1, 1, 1, 2, 4, 8, 3, 9, 27} ;
{execAlt[1], execAlt[2]}

Out[71]= {{{0, 1, 1, 2, 4, 8, 3, 9, 27}, Hold[S[1]]}, {Hold[Z[1]], {1, 1, 1, 2, 4, 8, 3, 9, 27}}}

Те же комментарии о изменчивости и зависимости от глобальной переменной также идут здесь. Эта последняя форма также более подходит для запроса типа функции:

getType[n_, lh_] := lh[[n]] /. {Hold[_Z] :> zType, Hold[_S] :> sType, _ :> unknownType}

например:

In[172]:= getType[#, listOfHeld] & /@ {1, 2}

Out[172]= {zType, sType}

Ответ 2

Первое, что волнует, - не использовать List, а скорее использовать что-то вроде этого:

 SetAttributes[lst, HoldAll];
 heldL=lst[Plus[1, 1], Times[2, 3]]

Там наверняка будет много более эрудированных предложений!

Ответ 3

Вы также можете использовать Hold для каждого элемента, который вы хотите сохранить:

a = {Hold[2 + 2], Hold[2*3]}

Вы можете использовать HoldForm для элементов или списка, если вы хотите, чтобы вид списка без Hold был видимым:

b = {HoldForm[2 + 2], HoldForm[2*3]}

c = [email protected]{2 + 2, 2*3}
   {2 + 2, 2 * 3}

И вы можете восстановить оцениваемую форму с помощью ReleaseHold:

a // ReleaseHold
b // ReleaseHold
c // ReleaseHold

Out[8]= {4, 6}

Out[9]= {4, 6}

Out[10]= {4, 6}

Форма Hold[2+2, 2*3] или тега a и b выше хороши, потому что вы можете легко добавлять термины, например. Append. Для типа b это логически:

Append[b, HoldForm[8/4]]

Для Hold[2+2, 2*3]:

Hold[2+2, 2*3] ~Join~ Hold[8/4]