To, co rozumiem przez „przezroczyste” przekazujące „opakowanie funkcji”, to funkcja, nazwijmy ją wrapper
, która zwraca wynik z przekazania całego argumentu do innej funkcji, nazwijmy ją wrappee
.
Jak to się robi w Emacs Lisp?
Uwaga: Idealna wrapper
funkcja jest niezależna od wrappee
podpisu funkcji; tzn. nie wie nic o liczbie, pozycjach, nazwach itp. wrappee
argumentów; po prostu przekazuje wszystkie swoje argumenty wrappee
, tak jakby wrappee
był pierwotnie nazywany. (Nie ma jednak potrzeby mieszania się ze stosem wywołań w celu zastąpienia połączenia wrapper
wywołaniem do wrappee
).
Zamieściłem częściową odpowiedź na moje pytanie:
(defun wrapper (&rest args) (apply 'wrappee args))
Działa to tylko wtedy, gdy niewrappee
jest interaktywne. Najwyraźniej sposób, w jaki funkcje interaktywne pobierają argumenty, reprezentuje inny „kanał” niż to, co obejmuje zaklęcie. Co jeszcze trzeba zatem jest equally- -agnostic odpowiednikiem podpisu dla przypadku, gdy stanowi interaktywny funkcji.(&rest args)
wrappee
(&rest args)
wrappee
(To pytanie było motywowane problemem opisanym w tym wcześniejszym pytaniu ).
Na wypadek, gdyby potrzebne było dalsze wyjaśnienie tego, o co proszę, poniżej znajduje się kilka przykładów pokazujących ekwiwalenty Pythona i JavaScript tego, czego szukam.
W Pythonie pokazano kilka standardowych sposobów implementacji takiego opakowania:
def wrapper(*args, **kwargs):
return wrappee(*args, **kwargs)
# or
wrapper = lambda *args, **kwargs: wrappee(*args, **kwargs)
(Tutaj *args
oznacza „wszystkie argumenty pozycyjne” i **kwargs
„wszystkie argumenty słów kluczowych”).
Odpowiednik JavaScript byłby mniej więcej taki:
function wrapper () { return wrappee.apply(this, arguments); }
// or
wrapper = function () { return wrappee.apply(this, arguments); }
Dla przypomnienia , nie zgadzam się, że to pytanie jest duplikatem Jak zastosować mapcar do funkcji z wieloma argumentami . Nie potrafię wyjaśnić, dlaczego, ponieważ te dwa pytania wyglądają tak wyraźnie dla mnie inaczej. To tak, jakby zapytano „wyjaśnij, dlaczego jabłko nie powinno być uważane za ekwiwalent pomarańczy”. Samo pytanie jest tak szalone, że można wątpić, czy można znaleźć odpowiedź, która zadowoli osobę zadającą pytanie.
advice
wystarczająco problematyczne, więc wolałbym trzymać się z daleka. W rzeczywistości motywem do tego pytania było znalezienie rozwiązania nierozwiązywalnego problemu, który mam z zalecaną funkcją ...interactive
specyfikację.Odpowiedzi:
Oczywiście jest to możliwe łącznie ze
interactive
specyfikacją. Mamy tu do czynienia z elisp ! (Lisp jest językiem, w którym najważniejszymi konstrukcjami są listy. Formy wywoływalne to tylko listy. Możesz je budować według własnych upodobań).Zastosowanie: Chcesz dodać funkcję do niektórych funkcji w sposób automatyczny. Rozszerzone funkcje powinny otrzymać nowe nazwy, więc
defadvice
nie ma to zastosowania.Najpierw wersja, która pasuje dokładnie do twojego celu. Ustawiamy funkcję cell (
fset
) symboluwrapper
ze wszystkimi wymaganymi informacjami zwrappee
i dodajemy nasze dodatkowe rzeczy.Działa dla obu
wrappee
definicji. Pierwsza wersjawrappee
jest interaktywna, druga nie.Ale wygodniej jest zdefiniować makro, które konstruuje rozszerzone funkcje. W ten sposób możemy nawet później podać nazwy funkcji. (Dobre dla wersji automatycznej).
Po wykonaniu poniższego kodu możesz dzwonić
wrapper-interactive
interaktywnie iwrapper-non-interactive
nieinteraktywnie.Uwaga: do tej pory nie znalazłem sposobu na przesłanie formularzy deklaracji, ale powinno to być również możliwe.
źródło
edebug
. Ponadto istnieją funkcje, w którychinteractive
-specyfikacja jest znacznie większa niż treść funkcji. W takich przypadkach przepisanieinteractive
specyfikacji może być dość nużące. Pytanie i odpowiedź dotyczą wymaganych zasad.Musiałem rozwiązać bardzo podobny problem
nadvice.el
, więc oto rozwiązanie (które wykorzystuje część kodu z nadvice.el):W porównaniu z innymi opublikowanymi dotychczas rozwiązaniami, to ma tę zaletę, że działa poprawnie, jeśli
wrappee
zostanie ponownie zdefiniowane przy użyciu innej interaktywnej specyfikacji (tj. Nie będzie nadal używać starej specyfikacji).Oczywiście, jeśli chcesz, aby opakowanie było naprawdę przezroczyste, możesz to zrobić po prostu:
źródło
advice-eval-interactive-spec
zgodnie z sugestią tutaj, mogę zbudować interaktywną specyfikację, która odpowiada temu dynamicznemu opakowaniu.called-interactively-p
zwrott
wwrappee
? Jest,funcall-interactively
ale nie maapply-interactively
(apply #'funcall-interactively #'wrappee args)
jeśli chcesz. Ale powinieneś to zrobić tylko wtedy, gdy funkcja jest wywoływana interaktywnie, więc coś takiego(apply (if (called-interactively-p 'any) #'funcall-interactively #'funcall) #'wrappee args)
.edit: Odpowiedź Tobiasza jest ładniejsza, ponieważ uzyskuje precyzyjną interaktywną formę i dokumentację zawiniętej funkcji.
Łącząc odpowiedzi Aarona Harrisa i kjo, możesz użyć czegoś takiego:
Stosowanie:
Opakowanie połączenia z jednym z:
M-x
wrapper-func
źródło