McCarthy'nin 1959 LISP'i
1959 yılının başlarında, John McCarthy, bir araya getirildiğinde günümüzde LISP benzeri tüm dillerin temelini oluşturan temel dokuz işlevi tanımlayan çığır açan bir makale yazdı. Kağıt burada dijital hale getirilebilir:
http://www-formal.stanford.edu/jmc/recursive.pdf
Yani, fonksiyonlar: İşiniz tam aynen 1960 yazısında açıklanan McCarthy'nin LISP için ayrıştırıcı ve tercüman uygulamaktır QUOTE
, ATOM
, EQ
, CAR
, CDR
, CONS
, COND
, LAMBDA
, ve LABEL
tüm işlevsel olmalıdır. Cevapların doğruluğunu göz önüne alırken, makale bu metnin önüne geçecek, ancak aşağıdaki dokuz işlevi özetlemeye çalıştım. Dilin ALL CAPS'ta olacağını ve hata kontrolünün gerekli olmadığını unutmayın, tüm girişlerin geçerli olduğu varsayılmalıdır.
Türleri
- McCarthy'nin LISP'sinde sadece iki tip vardır: Bir atom veya bir liste veya bir atom olabilen bir kafa olarak tekrar tekrar tanımlanmış bağlı bir liste ve kafanın bağlı olduğu bir liste (kuyruk).
NIL
Hem atom hem de liste olma özelliğine sahiptir. - Makaleye göre, atom isimleri sadece büyük harflerden, sayılardan ve boşluk karakterinden oluşacaktır, ancak ardışık boşluk dizeleri sadece bir boşluk olarak düşünülmeli ve tüm baştaki ve sondaki boşluk karakterleri kaldırılmalıdır. Örnek eşdeğer atom ismi (boşluk karakteri ile yerine alt çizgi)
___ATOM__1__ = ATOM_1
. Örnek eşdeğer olmayan atom isimleri:A_TOM_1 != ATOM_1
- Listeler parantez içinde gösterilir ve ima edilenler
NIL
her listenin sonundadır. Bir listedeki öğeler, çoğu modern Lisps'deki gibi boşluklarla değil , virgüllerle ayrılır. Yani liste(ATOM 1, (ATOM 2))
olurdu{[ATOM 1] -> {[ATOM 2] -> NIL} -> NIL}
.
QUOTE
:
- Bir atom (tek eleman) veya bağlantılı bir liste olabilen bir argüman alır. Argümanı tam olarak döndürür.
- Test durumları:
(QUOTE, ATOM 1) -> ATOM 1
(QUOTE, (ATOM 1, ATOM 2)) -> (ATOM 1, ATOM 2)
ATOM
:
- Bir atom (tek eleman) veya bağlantılı bir liste olabilen bir argüman alır. İade
T
bağımsız değişken bir atomu veya (eğer doğru)NIL
bağımsız değişken bir atom değilse (yanlış). - Test durumları:
(ATOM, (QUOTE, ATOM 1)) -> T
(ATOM, (QUOTE, (ATOM 1, ATOM 2))) -> NIL
EQ
:
- Atom olması gereken iki argüman alır (argümanlardan herhangi biri atom değilse, davranış tanımsızdır). İade
T
iki atomlu eşdeğer ya da eğer (doğru)NIL
bu değilse (yanlış). - Test durumları:
(EQ, (QUOTE, ATOM 1), (QUOTE, ATOM 1)) -> T
(EQ, (QUOTE, ATOM 1), (QUOTE, ATOM 2)) -> NIL
CAR
:
- Bir liste olması gereken bir argüman alır (bir liste değilse davranış tanımsızdır). Bu listenin ilk atomunu (kafa) döndürür.
- Test durumları:
(CAR, (QUOTE, (ATOM 1, ATOM 2))) -> ATOM 1
CDR
:
- Bir liste olması gereken bir argüman alır (bir liste değilse davranış tanımsızdır). Her atomu ancak listenin ilk atomunu, yani kuyruğunu döndürür. Her listenin bir örtük olarak sona erdiğine dikkat edin
NIL
, bu nedenleCDR
yalnızca bir öğeye sahip görünen bir listede çalıştırmanın geri döneceğini unutmayınNIL
. - Test durumları:
(CDR, (QUOTE, (ATOM 1, ATOM 2))) -> (ATOM 2)
(CDR, (QUOTE, (ATOM 1))) -> NIL
CONS
:
- İki argüman alır. Birincisi bir atom veya bir liste olabilir, ikincisi bir liste veya olmalıdır
NIL
. İlk argümanı ikinci argümana bağlar ve yeni oluşturulan listeyi döndürür. - Test durumları:
(CONS, (QUOTE, ATOM 1), (QUOTE, NIL)) -> (ATOM 1)
(CONS, (QUOTE, ATOM 1), (CONS, (QUOTE, ATOM 2), (QUOTE, NIL))) -> (ATOM 1, ATOM 2)
COND
:
- Bu, LISP'nin "if-else" tür ifadesidir. Her biri tam uzunlukta bir liste olması gereken değişken uzunluklu bir miktar argüman alır. Her bir argüman listesi için birinci terimi değerlendirin, eğer doğru ise (T), ilgili ikinci terimi geri getirin ve fonksiyondan çıkın. . İlk terim doğru değilse, bir sonraki argümana geçin ve koşulunu sınayın ve ilk gerçek koşula ulaşılana kadar devam edin. Argüman koşullarından en az birinin doğru olduğu varsayılabilir - hepsi yanlışsa, bu tanımsız davranıştır. Bu işlevin davranışına iyi bir örnek için sayfa 4'e bakınız.
- Test durumları:
(COND, ((ATOM, (QUOTE, ATOM 1)), (QUOTE, 1)), ((ATOM, (QUOTE, (ATOM 1, ATOM 2))), (QUOTE, 2))) -> 1
(COND, ((ATOM, (QUOTE, (ATOM 1, ATOM 2))), (QUOTE, 2)), ((ATOM, (QUOTE, ATOM 1)), (QUOTE, 1))) -> 1
LAMBDA
:
- Anonim bir işlev tanımlar. Birincisi, işlevin argümanlarını temsil eden atomların bir listesi ve ikincisi, genellikle argümanları kullanacak herhangi bir S ifadesi (işlev gövdesi) olan iki argüman alır.
- Test durumları:
- Anonim bir "isNull" işlevini tanımlama ve kullanma:
((LAMBDA, (ATOM 1), (EQ, ATOM 1, (QUOTE, NIL))), (QUOTE, NIL)) -> T
((LAMBDA, (ATOM 1), (EQ, ATOM 1, (QUOTE, NIL))), (QUOTE, ATOM 1)) -> NIL
LABEL
:
- Adsız bir
LAMBDA
işleve bir ad verir ; bu, aynı zamanda, bu işlevin özniteliği içinde yinelemeli olarak çağrılmasını sağlarLAMBDA
. İlki etiket, ikincisiLAMBDA
etiketin bağlı olması gereken işlev olan iki argüman alır . Sağlanan adı döndürür. TümLABEL
adların kapsamı geneldir ve a'nın yenidenLABEL
tanımlanması tanımsız bir davranıştır. - Eğlenceli gerçek,
LABEL
şu anda bu görevi başarmak içinLAMBDA
bir 'Y-Birleştiricisi' ile kullanılabildiğini bildiğimiz için özyinelemeli işlevler oluşturmak için aslında gerekli değil , ancak orijinal kağıdı yazarken McCarthy bu yöntemin farkında değildi. Programları zaten yazmak çok daha kolay hale getirir. - Test durumları:
(LABEL, SUBST, (LAMBDA, (X, Y, Z), (COND, ((ATOM, Z), (COND, ((EQ, Y, Z), X), ((QUOTE, T), Z))), ((QUOTE, T), (CONS, (SUBST, X, Y, (CAR, Z)), (SUBST, X, Y, (CDR, Z))))))) -> SUBST
- (yukarıdakileri çalıştırdıktan sonra)
(SUBST, (QUOTE, A), (QUOTE, B), (QUOTE, (A, B, C))) -> (A, A, C)
SUBST
Yukarıdaki fonksiyonun görselleştirilmesine yardımcı olmak için , bu Python benzeri sahte kod olarak gösterilebilir:
def substitute(x, y, z): # substitute all instances of y (an atom) with x (any sexp) in z
if isAtom(z):
if y == z:
return x
elif True:
return z
elif True:
return substitute(x,y,z[0]) + substitute(x,y,z[1:])
NİHAİ TEST CASE:
Doğru yazdıysam, tercümanının EVAL
bu kodla yorum yapabilmesi gerekir :
(LABEL, CAAR, (LAMBDA, (X), (CAR, (CAR, X))))
(LABEL, CDDR, (LAMBDA, (X), (CDR, (CDR, X))))
(LABEL, CADR, (LAMBDA, (X), (CAR, (CDR, X))))
(LABEL, CDAR, (LAMBDA, (X), (CDR, (CAR, X))))
(LABEL, CADAR, (LAMBDA, (X), (CAR, (CDR, (CAR, X)))))
(LABEL, CADDR, (LAMBDA, (X), (CAR, (CDR, (CDR, X)))))
(LABEL, CADDAR, (LAMBDA, (X), (CAR, (CDR, (CDR, (CAR, X))))))
(LABEL, ASSOC, (LAMBDA, (X, Y), (COND, ((EQ, (CAAR, Y), X), (CADAR, Y)), ((QUOTE, T), (ASSOC, X, (CDR, Y))))))
(LABEL, AND, (LAMBDA, (X, Y), (COND, (X, (COND, (Y, (QUOTE, T)), ((QUOTE, T), (QUOTE, NIL)))), ((QUOTE, T), (QUOTE, NIL)))))
(LABEL, NOT, (LAMBDA, (X), (COND, (X, (QUOTE, NIL)), ((QUOTE, T), (QUOTE, T)))))
(LABEL, NULL, (LAMBDA, (X), (AND, (ATOM, X), (EQ, X, (QUOTE, NIL)))))
(LABEL, APPEND, (LAMBDA, (X, Y), (COND, ((NULL, X), Y), ((QUOTE, T), (CONS, (CAR, X), (APPEND, (CDR, X), Y))))))
(LABEL, LIST, (LAMBDA, (X, Y), (CONS, X, (CONS, Y, (QUOTE, NIL)))))
(LABEL, PAIR, (LAMBDA, (X, Y), (COND, ((AND, (NULL, X), (NULL, Y)), (QUOTE, NIL)), ((AND, (NOT, (ATOM, X)), (NOT, (ATOM, Y))), (CONS, (LIST, (CAR, X), (CAR, Y)), (PAIR, (CDR, X), (CDR, Y)))))))
(LABEL, EVAL, (LAMBDA, (E, A), (COND, ((ATOM, E), (ASSOC, E, A)), ((ATOM, (CAR, E)), (COND, ((EQ, (CAR, E), (QUOTE, QUOTE)), (CADR, E)), ((EQ, (CAR, E), (QUOTE, ATOM)), (ATOM, (EVAL, ((CADR, E), A)))), ((EQ, (CAR, E), (QUOTE, EQ)), (EQ, (EVAL, (CADR, E, A)), (EVAL, (CADDR, E, A)))), ((EQ, (CAR, E), (QUOTE, COND)), (EVCON, (CDR, E), A)), ((EQ, (CAR, E), (QUOTE, CAR)), (CAR, (EVAL, (CADR, E), A))), ((EQ, (CAR, E), (QUOTE, CDR)), (CDR, (EVAL, (CADR, E), A))), ((EQ, (CAR, E), (QUOTE, CONS)), (CONS, (EVAL, (CADR, E), A), (EVAL, (CADDR, E), A))), ((QUOTE, T), (EVAL, (CONS, (ASSOC, (CAR, E), A), (EVLIS, (CDR, E), A)), A)))), ((EQ, (CAAR, E), (QUOTE, LABEL)), (EVAL, (CONS, (CADDAR, E), (CDR, E)), (CONS, (CONS, (CADAR, E), (CONS, (CAR, E), (CONS, A, (QUOTE, NIL))))))), ((EQ, (CAAR, E), (QUOTE, LAMBDA)), (EVAL, (CADDAR, E), (APPEND, (PAIR, (CADAR, E), (EVLIS, (CDR, E), A)), A))))))
(LABEL, EVCON, (LAMBDA, (C, A), (COND, ((EVAL, (CAAR, C), A), (EVAL, (CADAR, C), A)), ((QUOTE, T), (EVCON, (CDR, C), A)))))
(LABEL, EVLIS, (LAMBDA, (M, A), (COND, ((NULL, M), (QUOTE, NIL)), ((QUOTE, T), (CONS, (EVAL, (CAR, M), A), (EVLIS, (CDR, M), A))))))
O behemoth'u çalıştırdıktan sonra, bu satır geri dönmelidir (A, B, C)
:
(EVAL, (QUOTE, (CONS, X, (QUOTE, (B, C)))), (QUOTE, ((X, A), (Y, B))))
Bununla birlikte, John McCarthy'ye 16. sayfada kendisinden alıntı yapmak için bilgisayarında karakterleri tükeniyor gibi görünüyor:
Bilgisayarda daha fazla karakter varsa, önemli ölçüde geliştirilebilir ...
Bu nedenle, bu zorluk kod-golf olarak etiketlenmiştir ve karakterlerde en kısa cevap kazanacaktır. Standart boşluklar uygulanır. İyi şanslar!
Dize Değerlendirmeleri Üzerine Not : Bazılarının bir Lisp kullanarak ve ev sahibi diline uyacak şekilde sözdizimini değiştirerek ve ardından bir dize kullanarak bu zorluğu kazanmanın mümkün olabileceğini düşünüyorum (eval)
. Bu yaklaşımın, özellikle tanımlayıcı adlandırma kuralları ile mutlaka kazanacağına özellikle inanmadım ve dize eval
dilini tüm dillerde yasaklamanın öznel ve kaygan bir eğim olacağını düşünmeme rağmen . Ancak insanları bu meydan okumayı 'doğru' şekilde cezalandırmak istemem, bu yüzden bu sorun için iki kazanan, Lisp benzeri bir diğeri Lispy olmayan bir dilde, bu bir problem olursa .
((LAMBDA, (ATOM 1), (EQ, ATOM 1, (QUOTE, NIL))), (QUOTE, NIL)) -> NIL
nerede (QUOTE NIL)
sonunda girdi, bu nedenle bu dönmelidir T
?
-> NIL
CONS
"İkinci argümana ilk argümanı ekler ve yeni oluşturulan listeyi döndürür" demeniz gerekir, ancak sınama durumları birinciye eklenen ikinci argümanı gösterir. Hangisi doğru?