Набор перегрузки [a, b] (a = b) - PullRequest
3 голосов
/ 04 мая 2011

Я бы хотел перегрузить функцию Set в Mathematica (=), которая оказалась для меня слишком сложной (см. Следующий пример кода).Я успешно перегружен другими функциями (например, Reverse в примере кода).Есть предложения?

In[17]:= ClearAll[struct];

In[18]:= var1=struct[{1,2}]
Out[18]= struct[{1,2}]

In[19]:= Reverse@var1
Out[19]= struct[{1,2}]

In[20]:= Head[var1]
Out[20]= struct

In[21]:= struct/:Reverse[stuff_struct]:=struct[Reverse@stuff[[1]]]

In[22]:= Reverse@var1
Out[22]= struct[{2,1}]

In[23]:= struct/:Set[stuff_struct,rhs_]:=Set[struct[[1]],rhs]

In[24]:= var1="Success!"
Out[24]= Success!

In[25]:= var1
Out[25]= Success!

In[26]:= Head[var1]
Out[26]= String

In[27]:= ??struct
Global`struct
Reverse[stuff_struct]^:=struct[Reverse[stuff[[1]]]]

(stuff_struct=rhs_)^:=struct[[1]]=rhs

Ответы [ 2 ]

8 голосов
/ 04 мая 2011

Я не думаю, что то, что вы хотите, можно сделать с помощью 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* - атрибуты и связанные с ними вопросы во многих местах, например здесь и здесь

1 голос
/ 05 мая 2011

Я также не верю, что это можно сделать с помощью TagSet, поскольку должен храниться первый аргумент Set.

Мне кажется, что при изменении Set это может бытьсделано с:

Unprotect[Set]

Set[s_, x_] /; Head[s] === struct := s[[1]] = x

Однако Леонид знает Mathematica лучше меня, и у него, вероятно, есть веская причина для более длинного определения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...