McCarthy'nin LISP'i


39

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 LABELtü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). NILHem 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 NILher 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 Tbağımsız değişken bir atomu veya (eğer doğru) NILbağı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 Tiki atomlu eşdeğer ya da eğer (doğru) NILbu 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 nedenle CDRyalnızca bir öğeye sahip görünen bir listede çalıştırmanın geri döneceğini unutmayın NIL.
  • 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 LAMBDAişleve bir ad verir ; bu, aynı zamanda, bu işlevin özniteliği içinde yinelemeli olarak çağrılmasını sağlar LAMBDA. İlki etiket, ikincisi LAMBDAetiketin bağlı olması gereken işlev olan iki argüman alır . Sağlanan adı döndürür. Tüm LABELadların kapsamı geneldir ve a'nın yeniden LABELtanımlanması tanımsız bir davranıştır.
  • Eğlenceli gerçek, LABELşu anda bu görevi başarmak için LAMBDAbir '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)

SUBSTYukarı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 EVALbu 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 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 evaldilini 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 .


1
Bir "IsNull" işlevini tanımlayan bir Lambda örneğiniz var, ancak Nil dönüşü Nil'e benziyor, bana göründüğü gibi görünüyor ki T?
nmjcman101

1
You have ((LAMBDA, (ATOM 1), (EQ, ATOM 1, (QUOTE, NIL))), (QUOTE, NIL)) -> NILnerede (QUOTE NIL)sonunda girdi, bu nedenle bu dönmelidir T?
nmjcman101

1
Doğru, ama sen -> NIL
yazdın

1
Açıklamanızda, 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?
Jordan

1
Uygulamamı kjetilvalle'ın lisp öğreticisine dayandırıyorum ve sözdizimi biraz farklı. Küçük harf kullanılır ve virgül yoktur. Sadece küçük harf dönüşümü yapabilir ve yukarıdaki tercümanın tasarımına az ya da çok uyacak şekilde giriş dizesinden virgülleri kaldırabilir miyim? Lisp için çok yeniyim, ancak bu zorluğu kendi dilimle keşfetmek istedim. Şimdiye kadar ayrıştırıcı uygulandı . (
Dilim Lisp'a

Yanıtlar:


17

Python 3, 770 bayt

Bu stdin / stdout'taki bir REPL. Her satırın tam ifade veya boş olmasını bekler. evalUygulamayı kısaltmak için kullanılır, ancak mantık için gerekli değildir.

import re,sys;S=re.sub
P=lambda l:eval(S("([A-Z0-9][A-Z0-9 ]*)",r"' '.join('\1'.strip().split())",S("NIL","()",S("\)",",)",l))))
d={"QUOTE":'(v,L[1])[1]',"EQ":'[(),"T"][E(L[1],v)==E(L[2],v)]',
"CDR":'E(L[1],v)[1:]',"CONS":'(E(L[1],v),)+E(L[2],v)',"CAR":'E(L[1],v)[0]',
"LAMBDA":'("#",)+L[1:]',"LABEL":'[v.update({L[1]:E(L[2],v)}),L[1]][1]'}
def E(L,v):
 if L*0=="":return v[L]
 elif L[0]in d:return eval(d[L[0]])
 elif L[0]=="COND":return next(E(l[1],v)for l in L[1:]if E(l[0],v)=="T")
 elif L[0]=="ATOM":o=E(L[1],v);return[(),"T"][o*0in["",o]]
 else:l=E(L[0],v);n=v.copy();n.update({a:E(p,v)for a,p in zip(l[1],L[1:])});return E(l[2],n)
R=lambda o:o==()and"NIL"or 0*o==()and"(%s)"%", ".join(R(e)for e in o)or o
g={}
for l in sys.stdin:
 if l.strip():print(R(E(P(l),g)))

1
@Harry İlk iki test durumu son dokunuşlarda ortaya koyduğum küçük bir hatayı düzelttikten sonra çalışıyor. Değerlendirme kusursuz çalışıyor. Fakat SUBSTörnek hala (bildiğim kadarıyla) bir test çantası olarak bozuldu. Biri CONDs bir bulmadan sonuna geldiğinde T.
orlp

1
Bunu düzelttiğin için teşekkürler! Bu çok etkileyici! Şu anda benim için tüm test şovlarında işe yarıyor, EVAL(çok hoş bir sürpriz ilk denememde bir hakkım oldu!) Size şimdi ödül ve kabul edilen cevabı vereceğim!
Harry

2
Ayrıca R(E(P(l)kurulumu seviyorum ;-)
Harry

2
@Harry Şaka yapıyorum ki bu bir kazaydı! R = repr, E = eval, P = parse, l = line.
orlp

4
Sadece size bildirmek istedim, burada uygulamanızı anlatan bir makale yazdım !
Harry
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.