2009-06-25 12 views
5

Peter Norvig w PAIP mówi:
„w nowoczesnych lisps ... eval jest stosowany rzadziej (w rzeczywistości w schemacie nie ma w ogóle eval)” "jeśli znajdziesz się za pomocą eval, ty prawdopodobnie robią coś niewłaściwego ".EVAL na schemacie

Jakie są sposoby obejścia używania eval w schemacie? Czy w takim przypadku eval jest absolutnie konieczny?

Odpowiedz

7

Są przypadki, w których konieczne jest eval, ale zawsze zawierają zaawansowane programy, które powodują dynamiczne ładowanie kodu (np. Serwletu na serwerze WWW). Jeśli chodzi o sposób na "obchodzenie" używania go - to zależy od faktycznego problemu, który próbujesz rozwiązać, nie ma magicznego rozwiązania pozwalającego uniknąć eval z wyjątkiem ... eval.

(BTW, wydaje mi się, że PAIP został napisany dawno temu, zanim eval został dodany do raportu Scheme).

+0

Przykro mi, nie mogłem być bardziej szczegółowy o tym, co chciałem w pytaniu. Ale co ciekawe, zawsze uważałem, że eval zawsze był integralną częścią Schematu. W każdym razie mam nadzieję, że zobaczę więcej użycia i "nadużyć" eval w CS G111. :) – unj2

+1

Tak, 'eval' * jest * integralną częścią schematu, ale jest naprawdę potrzebny tylko w zaawansowanych przypadkach. Zasada jest taka: jeśli nie znasz przyczyn technicznych, które wymagają użycia 'eval', to * nie musisz tego * potrzebować. (A to jest poważna odpowiedź!) W każdym razie, tak, będziesz miał dużo "ewaluacji" w CSG111, jeśli masz zamiar wziąć to, i mam nadzieję, jeśli pamiętasz, zapytaj mnie o to. –

1

Po pierwsze, PAIP jest napisane dla Common Lisp, a nie dla Schematu, więc nie wiem, czy powiedziałby to samo. Makra CL działają podobnie jak eval, ale w czasie kompilacji zamiast w czasie wykonywania, i są inne rzeczy, które możesz zrobić. Gdybyś pokazał mi przykład użycia eval w Common Lisp, mógłbym spróbować wymyślić inne metody robienia tego samego.

Nie jestem programistą Scheme. Mogę mówić tylko z perspektywy Norviga, jako programista Common Lisp. Nie sądzę, żeby mówił o Planie, i nie wiem, czy znał i znał szczególnie Schemat.

Po drugie, Norvig mówi "prawdopodobnie robisz coś niewłaściwego" zamiast "robisz coś niewłaściwego". Oznacza to, że dla wszystkich, których zna, są chwile, kiedy eval jest właściwą rzeczą do użycia. W języku takim jak C, powiedziałbym to samo o goto, chociaż są one całkiem przydatne w niektórych ograniczonych okolicznościach, ale większość użytkowników korzysta z nich przez osoby, które nie znają się lepiej.

+0

"Nie wiem, czy zna on szczególnie dobrze Program". To stwierdzenie jest niewiarygodne. "zdarzają się sytuacje, w których warto używać eval". To było moje drugie pytanie. Czy jako programiści użyliście eval? – unj2

+1

Oczywiście, Norvig jest bardzo dobry w Common Lisp, po napisaniu naprawdę świetnej książki na ten temat. Nie dotyczy to Schematu. Czy Stroustrup koniecznie byłby dobrym autorytetem w sprawie najlepszego sposobu na zrobienie czegoś w Javie lub Objective-C? Ta rodzina języków nie jest bardziej rozproszona niż rodzina Lisp, w tym Common Lisp and Scheme. –

+0

hmmm on realizuje schemat w lisp ... no cóż, nie wiem. ale zakładam, że leży w spektrum "zna szczególnie dobrze". – unj2

-1

Można napisać interpreter schematu w schemacie. Jest to z pewnością możliwe, ale nie jest praktyczne.

To jest ogólna odpowiedź, ponieważ nie mam używanego schematu, ale może ci to pomóc. :)

+0

To nie jest miejsce w pobliżu odpowiedzi, której szukałem. :) – unj2

4

Myli się. Oczywiście w Schemacie jest eval.

+0

Który schemat? Nie sądzę, żeby r4rs wymagał eval, aby w ogóle był obecny. – Aaron

+3

R5RS http://schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.5 – newacct

+3

@newacct PAIP przyszedł w 1992 roku i R4RS nie miał eval. R5Rs przyszedł w 1998 roku i dodał eval, dynamiczny wiatr i wartości :) – Sylwester

0

Jednym z zastosowań Widziałem na „eval” w środowiskach skryptowych jest parametryzacji niektórych kod z wartościami wykonawczymi. na przykład w psuedo-C:

param = read_integer(); 
fn = eval("int lambda(int x) { 
      int param = " + to_string(param) + "; 
      return param*x; }"); 

Mam nadzieję, że okaże się to naprawdę brzydkie. Wklejanie ciągów w celu utworzenia kodu w czasie wykonywania? Ick. W Scheme i innych leksykalnych Lisps, możesz sparametryzować funkcje bez użycia eval.

(define make-my-fn 
    (lambda (param) 
    (lambda (x) (* param x))) 

(let* ([ param (read-integer) ] 
     [ fn  (make-my-fn param ]) 
    ;; etc. 
) 

Jak wspomniano, dynamiczne ładowanie kodu i takie wciąż wymagają eval, ale sparametryzowany kod i skład kodu mogą być produkowane z pierwszorzędnymi funkcjami.

3

Będziesz potrzebował eval w bardzo rzadkim przypadku. Przypadek, który przychodzi na myśl pierwszy, polega na tym, że zbudujesz program za pomocą programu, a następnie go wykonasz. Dzieje się tak na przykład w przypadku algorytmu genetycznego na przykład. W tym przypadku budujesz dużo losowych programów, które będziesz musiał wykonać.Posiadanie eval w połączeniu z kodem będącym danymi sprawia, że ​​seplenienie jest najłatwiejszym językiem programowania do wykonywania algorytmu genetycznego.

Posiadanie tych właściwości wiąże się z dużymi kosztami (pod względem szybkości i rozmiaru programu), ponieważ usuniesz wszystkie możliwości optymalizacji czasu kompilacji na kodzie, który zostanie oceniony, i musisz zachować pełny interpreter w Twój wynikowy plik binarny.

W związku z tym uważa się, że złym rozwiązaniem jest użycie eval, gdy można tego uniknąć.

3

Twierdzenie, że Schemat nie ma numeru eval, jest niedokładne przynajmniej dla najnowszych wersji standardu Scheme (R5RS i późniejszych). Zwykle jest to makro, które generuje kod w czasie kompilacji.

To prawda, że ​​należy unikać eval. Na początek, nigdy nie widziałem zadowalającej definicji tego, jak powinien się zachowywać, na przykład:

  1. Jakich wyrażeń środowiska należy oceniać, gdy nie przekazuje się środowiska?
  2. Po przejściu w środowisku, jak one działają? Na przykład standardy nie określają sposobu, w jaki można wstępnie powiązać wartość w tym obiekcie środowiska.

To powiedziawszy, ja pracowałem z zastosowania schematu, który używa eval do generowania kodu dynamicznie w czasie wykonywania, w przypadku gdy struktura obliczeń nie mogą być znane w czasie kompilacji. Chodziło o to, aby system Scheme do kompilował kod w czasie wykonywania ze względów wydajnościowych - a trudność polega na tym, że nie ma standardowego sposobu poinformowania systemu Scheme "o kompilacji tego kodu".

Należy również pamiętać, że eval może stanowić ogromne zagrożenie bezpieczeństwa. Nigdy nie powinieneś nigdy dodawać niczego, co nie ma ogromnej ściany oddzielenia od danych wprowadzanych przez użytkownika. Zasadniczo, jeśli chcesz bezpiecznie używać eval, powinieneś to zrobić w kontekście fazy generowania kodu systemu podobnego do kompilatora, po tym, jak przeanalizowałeś niektóre dane wejściowe (używając wszechstronnie zdefiniowanej gramatyki!).