Smalltalk ma czas whileTrue: -Message realizowane poprzez rekursję (w VisualWorks) lub poprzez inline kompilacji (w Squeak/Pharo). Czy istnieje sposób zdefiniowania takiej metody bez użycia jednego z nich? Jeśli nie, czy istnieje dowód na to, że można to osiągnąć?Czy istnieje sposób w języku komunikatów, aby zdefiniować wiadomośćTrueTree bez rekursji lub sztuczek kompilatora?
Odpowiedz
whileTrue: & whileFalse: zawsze zwraca zero. np. jeśli nie jest to normalny rekurencyjna definicja:
whileTrue: aBlock
^self value ifTrue: [self whileTrue: aBlock]
ifTrue: zwróci nil, jeśli wartość samo jest fałszywe, a więc wartość powinna być zawsze zero. Znajduje to odzwierciedlenie w optymalizacji kompilatora. Oryginalny blue book Smalltalk-80 V2 definicja jest
whileTrue: aBlock
"Evaluate the argument, aBlock, as long as the value
of the receiver is true. Ordinarily compiled in-line.
But could also be done in Smalltalk as follows"
^self value
ifTrue:
[aBlock value.
self whileTrue: aBlock]
Więc po prostu zmienić, aby
BlockContext>>myWhileTrue: aBlock
| start |
start := thisContext pc.
self value ifFalse: [^nil ].
aBlock value.
thisContext pc: start
lub ??
BlockContext>>myWhileTrue: aBlock
| start |
start := thisContext pc.
^self value ifTrue:
[aBlock value.
thisContext pc: start]
Ale niestety obie te katastrofy VM kiedyś po drugiej iteracji ponieważ thisContext pc nie odpowiada komputera na następnej iteracji, ale zamiast cokolwiek wierzchołek stosu jest :)
Jednak następujące działa:
ContextPart methods for controlling
label
^{ pc. stackp }
goto: aLabel
"N.B. we *must* answer label so that the
top of stack is aLabel as it is when we send label"
pc := aLabel at: 1.
self stackp: (aLabel at: 2).
^aLabel
BlockContext>>myWhileTrue: aBlock
| label |
label := thisContext label.
self value ifFalse: [^nil].
aBlock value.
thisContext goto: label
BlockClosure>>myWhileTrue: aBlock
| label |
label := thisContext label.
^self value ifTrue:
[aBlock value.
thisContext goto: label]
proponuję następujące rozwiązanie:
BlockContext>>myWhileTrue: aBlock
| start |
start := thisContext pc.
self value ifFalse: [^self ].
aBlock value.
thisContext pc: start
Zamiast rekursji i kompilator sztuczek, powyższy kod wykorzystujący odbicie na stosie wykonania. Przed rozpoczęciem pętli metoda przechowuje bieżący licznik programu w zmiennej tymczasowej i resetuje go na końcu, aby powrócić do początku metody. W niektórych implementacjach Smalltalk takie podejście może być powolne, ponieważ niektóre dialekty Smalltalk potwierdzają tylko stos na żądanie, ale w Pharo/Squeak ta sztuczka jest całkiem praktyczna.
Uwaga, powyższy kod nie odpowiada na wynik ostatniej aktywacji bloku, ponieważ oryginalna implementacja #whileTrue: robi. Jednak powinno to być łatwe do naprawienia.
Można również użyć procedury obsługi wyjątku, aby wrócić do początku, ale może to być traktowane jako oszustwo, jeśli kod obsługi wyjątków użyty został po raz drugi: lub w innym miejscu. Zasadniczo, pytanie sprowadza się do tego, czy można zaimplementować pętlę bez goto lub rekursji i myślę, że odpowiedź na to pytanie brzmi "nie". Więc jeśli rekursja jest zabroniona, pozostaje ci próba zgarnięcia razem technik, takich jak ustawianie metody PC lub użycie wyjątku.
Wystarczy zrobić:
BlockClousure >> WhileTrue: aBlock
wartość własna ifTrue: [ Wartość aBlock. thisContext restart. "restart na pharo, reset na VW"]
- 1. Czy istnieje limit rekursji w seplenienie?
- 2. Czy istnieje sposób, aby sprawdzić, czy wartości nie numerycznej makro
- 3. W języku C lub C++, czy istnieje sposób na rozszerzenie klasy bez dziedziczenia?
- 4. Czy istnieje sposób, aby Asio działał bez Boost?
- 5. Rozszerzanie kompilatora Mono C#: czy istnieje jakakolwiek dokumentacja lub precedens?
- 6. znajdowanie bez rekursji
- 7. Czy istnieje sposób, aby skomentować lub lepiej zorganizować plik bower.json?
- 8. Przełącznik kompilatora do włączania/wyłączania komunikatów debugowania?
- 9. Czy istnieje sposób na poprawę wydajności wielordzeniowej/wieloprocesorowej kompilatora Java?
- 10. Czy istnieje sposób, aby zignorować odpowiedź formularza?
- 11. Czy istnieje sposób, aby wyczyścić django.db.connection.queries?
- 12. Czy istnieje sposób, aby zleceniowe NSWindow spacjami
- 13. Czy istnieje funkcja w języku Java, aby uzyskać średnią ruchomą
- 14. Android przechwycić SMS bez komunikatów ikona powiadomienia lub WAP-Push
- 15. Czy istnieje sposób zdefiniowania zmiennej w LaTeX?
- 16. Czy istnieje sposób, aby anulować TabControl.Items.CurrentChanging?
- 17. Czy istnieje sposób, aby uciszyć rejestrowanie hsqldb?
- 18. Czy istnieje metoda w języku Java, aby zainicjować zestaw po kroku 1 lub innej długości?
- 19. Czy istnieje sposób, aby Resharper traktować Trace.Assert jak Debug.Assert?
- 20. Jaki jest właściwy sposób na wdrożenie bardzo głębokiej rekursji w języku Ruby w sposób * czysty *?
- 21. Czy istnieje sposób, aby zapobiec zaokrąglaniu stringWithFormat?
- 22. Czy istnieje sposób symulacji kliknięcia alertu w języku JavaScript?
- 23. Czy można zmienić listę w zagnieżdżony dyktat kluczy * bez * rekursji?
- 24. Parsowanie ciągu znaków w języku C#; czy istnieje czystszy sposób?
- 25. Czy istnieje przenośny sposób kopiowania bloku pamięci w języku C#?
- 26. Czy w języku Java istnieje odpowiednik epollu?
- 27. Czy istnieje sposób, aby posłuchać innej metody klasy?
- 28. Czy istnieje sposób na znalezienie ID Teamviewer w języku C#?
- 29. Czy istnieje prostszy sposób niejawnego używania interfejsów w języku F #?
- 30. Dlaczego przeglądarki nie są na tyle inteligentne, aby sprzęt przyspieszył bez żadnych sztuczek?
Jesteś zawsze pomoc, dzięki Lukas :) –
W tym przypadku przywrócenie kontekstu jest w zasadzie odpowiednikiem GOTO –
Bez nieskończonej rekursji, bez nieskończonej liczby instrukcji i bez możliwość wznowienia kontekstu wydaje się niemożliwa. –