2011-04-30 5 views
5

Jak uzyskać wszystkie definicje symboli powiązanych z innymi symbolami: TagSet, TagSetDelayed, UpSet lub UpSetDelayed?Jak uzyskać wszystkie definicje związane z innymi symbolami?

Na przykład, jeśli ktoś określił

area[square] ^= s^2 
area[cube] ^= 6*s^2 

jak uzyskać te definicje, nie znając nazwisk square, cube ale znając tylko nazwę area?


właśnie odkryli, że UpValues nie zwraca definicje dla MakeBoxes i N ponieważ są one przechowywane w FormatValues i NValues odpowiednio:

In[1]:= rotate /: MakeBoxes[expr_rotate, "StandardForm"] := x 
UpValues[rotate] 
FormatValues[rotate] 

Out[2]= {} 

Out[3]= {HoldPattern[MakeBoxes[expr_rotate, "StandardForm"]] :> x} 

In[4]:= pi /: N[pi] = 3.14 
UpValues[pi] 
NValues[pi] 

Out[4]= 3.14 

Out[5]= {} 

Out[6]= {HoldPattern[N[pi, {MachinePrecision, MachinePrecision}]] :> 
    3.14} 

W ten sposób zamiast UpValues powinniśmy użyć kombinacji UpValues, FormatValues i NValues.


Podczas próby wyjścia listę FormatValues można problemy ze MakeBoxes od FormatValues daje definicje MakeBoxes tych are further processed by MakeBoxes on creating the output for the FrontEnd. Ten problem można rozwiązać, tymczasowo przełączając FormatType na OutputForm lub konwertując te definicje na ciągi.

In[1]:= SetOptions[$Output,FormatType->OutputForm]; 
FormatValues[DialogNotebook] 
Out[2]= {HoldPattern[MakeBoxes[BoxForm`apat$:HoldPattern[DialogNotebook[___]], BoxForm`fpat$_]] :> 

    BoxForm`BoxFormAutoLoad[MakeBoxes, BoxForm`apat$, BoxForm`fpat$, Typeset`CellNotebook`, 

    {{CellGroup, _}, {DocumentNotebook, _}, {PaletteNotebook, _}, {DialogNotebook, _}, {ExpressionCell, _}, {Text, _}, 

    {TextCell, _}, {Cell, HoldPattern[MakeExpression[_Cell, _]]}, {Notebook, HoldPattern[MakeExpression[_Notebook, _]]}}]} 

In[1]:= [email protected][DialogNotebook] 
Out[1]= {HoldPattern[MakeBoxes[BoxForm`apat$:HoldPattern[DialogNotebook[___]], BoxForm`fpat$_]] :> BoxForm`BoxFormAutoLoad[MakeBoxes, BoxForm`apat$, BoxForm`fpat$, Typeset`CellNotebook`, {{CellGroup, _}, {DocumentNotebook, _}, {PaletteNotebook, _}, {DialogNotebook, _}, {ExpressionCell, _}, {Text, _}, {TextCell, _}, {Cell, HoldPattern[MakeExpression[_Cell, _]]}, {Notebook, HoldPattern[MakeExpression[_Notebook, _]]}}]} 
+0

Czy ostatnio edytujesz prośbę o zaktualizowaną odpowiedź lub opublikowano ją tylko po to, aby pomóc innym znaleźć to pytanie? –

+0

@ Mr.Wizard Myślę, że lepiej byłoby zaktualizować odpowiedź za pomocą kompletnego rozwiązania. –

+0

@ Mr.Wizard Problem jest naprawdę trudny. Zobacz edytowaną część mojego pytania. Teraz rozumiem, dlaczego programiści przenieśli wszystkie definicje 'MakeBoxes' do ledwo udokumentowanych' FormatValues'. :) –

Odpowiedz

4

Próbując rozwiązać problemy Aleksieja z odpowiedzią Howarda, wpadłem na to:

Cases[ 
    UpValues @@@ MakeExpression /@ Names["Global`*"], 
    HoldPattern[[email protected]_area :> _], 
    {2} 
] 

w odpowiedzi na zaktualizowanych wymagań, o to zaawansowana wersja:

SetAttributes[otherValues, HoldFirst] 

otherValues[sym_] := 
    With[{names = MakeExpression /@ Names["Global`*"]}, 
    Join[ 
     Cases[UpValues @@@ names, HoldPattern[[email protected]_sym :> _], {2}], 
     Cases[NValues @@@ names, HoldPattern[[email protected][sym, ___] :> _], {2}], 
     Select[Join @@ FormatValues @@@ names, ! FreeQ[#, [email protected]] &] 
    ] 
    ] 
+1

Myślę, że to rozwiązanie jest dość eleganckie! –

+0

Zarówno twoje, jak i @ Leonida rozwiązania oceniają 'obszar'. Można tego uniknąć, zawijając go za pomocą 'HoldPattern':' HoldPattern [area] [_] '. Po tym kod staje się prawie bezpieczny. Jedyny egzotyczny przypadek, kiedy staje się niebezpieczny, to gdy definiujemy 'area [surprise] ^: = Unevaluated [Evaluate [Print [" Surprise! :) "]]]'. W tym szczególnym przypadku obie wersje oceniają definicję. Ale myślę, że nie powinniśmy powszechnie dbać o egzotykę tego hakera. –

+0

@Alexey, kiedy "obszar" ma wartość? Jeśli przypiszę 'area [square]^= s^2', a następnie 'area = 5', a potem ocenię' area [square] 'otrzymam' 5 [square] '. –

3

Można spróbować wyczerpującego przeszukiwania poprzez

Select[UpValues /@ Cases[ToExpression[Names["*"]], _Symbol], ! FreeQ[#, area] &] 

który w swoim przykładzie przyniesie

{{HoldPattern[area[cube]] :> 6 s^2}, {HoldPattern[area[square]] :> s^2}} 
+1

Ten kod jest niebezpieczny, ponieważ każdy z symboli w '$ ContextPath' jest obliczany! Powinien istnieć sposób, aby to zrobić bez oceny symboli. Innym problemem jest to, że ten kod zwróci także definicje mające 'square' na r.h.s. lub na l.h.s, ale nie na pozycji 'Head' podwyrażonego wewnątrz' HoldPattern'. Ale i tak dziękuję. –

3

Poniższa wersja

Cases[ 
    [email protected][ 
    ToExpression[#, InputForm, Function[sym, UpValues[sym], HoldAllComplete]] &, 
    Names["Global`*"]], 
    Verbatim[RuleDelayed][Verbatim[HoldPattern][_area], _] 
] 

nie oceni symbole, jak również. Jest podobny w duchu do @Mr. Odpowiedź czarodzieja, ale wolę ToExpression na MakeExpression, ponieważ ta ostatnia jest powiązana z FrontEnd i ramkami (przynajmniej koncepcyjnie), podczas gdy pierwsza jest poleceniem ogólnego przeznaczenia (chociaż jest wspomniane w dokumentacji, że będzie używać reguł dla MakeExpression) .

Jeśli masz dostęp do pełnego Mathematica od początku sesji, innym rozwiązaniem byłoby przeładowywać TagSet, TagSetDelayed, UpSet i UpSetDelayed tak, że będą nagrywać zależności symbol w jakiś hash.Oto przykład dla UpSet:

Unprotect[UpSet]; 
Module[{tried, upsetHash}, 
    upsetHash[_] = {}; 
    getUpsetHash[] := upsetHash; 
    UpSet[f_[args___], rhs_] := 
    Block[{tried = True}, 
     AppendTo[upsetHash[f], 
      Select[HoldComplete[args], 
      Function[Null, Head[Unevaluated[#]] === Symbol, HoldAll]]]; 
     UpSet[f[args], rhs]] /; ! TrueQ[tried] 
]; 
Protect[UpSet]; 

Wszystkie zadania wykonane z UpSet po to redefinicja będą rejestrowane. Na przykład, po wykonaniu swój przykład powyżej, możesz zadzwonić

In[6]:= getUpsetHash[][area] 

Out[6]= {HoldComplete[square], HoldComplete[cube]} 

W ten sposób można uzyskać informacje o wiele szybciej, zwłaszcza jeśli chcesz, aby takie pytania często i/lub masz dużo pakietów obciążonych. Możesz także zautomatyzować proces dalej, aby przełączyć się na standardowe definicje przypisań po załadowaniu interesującej funkcji.

+0

Nie rozumiem twojego sprzeciwu wobec MakeExpression, ale nauczyłem się słuchać, kiedy mówisz. Czy wytłumaczysz dalej? Ponadto, dlaczego potrzebujesz 'Function [sym, UpValues ​​[sym], HoldAllComplete]'? –

+0

@ Mr.Wizard Ta funkcja jest potrzebna do zawijania wyników "ToExpression" bez ich oceny. 'MakeExpression' opakowuje swoje dane wyjściowe w' HoldComplete' przed domyślną oceną.BTW Myślę, że w tym konkretnym przypadku atrybut "HoldFirst' jest całkiem wystarczający. –

+0

@Alexey, czy uważasz, że moja odpowiedź nie jest pomocna? W każdym razie nadal nie widzę potrzeby dla tej części kodu. Z Pomocy: "ToExpression [input, form, h] owija głowę h wokół wyrażenia wytworzonego przed jej oceną." Dlatego myślę, że 'ToExpression [#, InputForm, UpValues]' powinny działać. –

Powiązane problemy