Я не думаю, что то, что вы хотите, можно сделать с помощью UpValues
(увы), поскольку символ (тег) должен быть не глубже первого уровня, чтобы определение работало. Кроме того, семантика, которую вы хотите, несколько необычна в Mathematica, поскольку большинство выражений Mathematica являются неизменяемыми (не L-значениями), и их частям нельзя присваивать значения. Я считаю, что этот код будет делать что-то похожее на то, что вы хотите:
Unprotect[Set];
Set[var_Symbol, rhs_] /;
MatchQ[Hold[var] /. OwnValues[var], Hold[_struct]] := Set[var[[1]], rhs];
Protect[Set];
Например:
In[33]:= var1 = struct[{1, 2}]
Out[33]= struct[{1, 2}]
In[34]:= var1 = "Success!"
Out[34]= "Success!"
In[35]:= var1
Out[35]= struct["Success!"]
Но, как правило, добавление DownValues
к таким важным командам, как Set
, не рекомендуется, так как это может привести к незначительному повреждению системы.
EDIT
Немного поясним, почему ваша попытка не удалась: Mathematica реализует операторы управления потоком и присваивания с использованием механизма удержания аргументов (Hold*
- атрибуты, описанные здесь ). Этот механизм позволяет, в частности, имитировать семантику передачи по ссылке, необходимую для назначений. Но тогда, когда вы присваиваете var1
, Set
не знает, что уже хранится в var1
, поскольку имеет только символ var1
, а не его значение. Шаблон _struct
не соответствует, потому что, даже если переменная уже хранит некоторые struct
, Set
имеет только имя переменной. Чтобы совпадение было успешным, переменная внутри Set
должна была бы оценить его значение. Но тогда значение является неизменным, и вы не можете присвоить ему. Код, который я предложил, проверяет, имеет ли переменная присвоенное значение в форме struct[something]
, и, если это так, изменяет первую часть (команда Part
является исключением, она может изменять части выражения L-значения при условии что эти части уже существуют).
Вы можете прочитать больше на темы Hold*
- атрибуты и связанные с ними вопросы во многих местах, например здесь и здесь