Ortak Lisp, 560 bayt
"Sonunda bir kullanım buldum PROGV
."
(macrolet((w(S Z G #1=&optional(J Z))`(if(symbolp,S),Z(destructuring-bind(a b #1#c),S(if(eq a'L),G,J)))))(labels((r(S #1#(N 97))(w S(symbol-value s)(let((v(make-symbol(coerce`(,(code-char N))'string))))(progv`(,b,v)`(,v,v)`(L,v,(r c(1+ n)))))(let((F(r a N))(U(r b N)))(w F`(,F,U)(progv`(,b)`(,U)(r c N))))))(p()(do((c()(read-char()()#\)))q u)((eql c #\))u)(setf q(case c(#\S'(L x(L y(L z((x z)(y z))))))(#\K'(L x(L u x)))(#\I'(L a a))(#\((p)))u(if u`(,u,q)q))))(o(S)(w S(symbol-name S)(#2=format()"~A.~A"b(o c))(#2#()"~A(~A)"(o a)(o b)))))(lambda()(o(r(p))))))
Ungolfed
;; Bind S, K and I symbols to their lambda-calculus equivalent.
;;
;; L means lambda, and thus:
;;
;; - (L x S) is variable binding, i.e. "x.S"
;; - (F x) is function application
(define-symbol-macro S '(L x (L y (L z ((x z) (y z))))))
(define-symbol-macro K '(L x (L u x)))
(define-symbol-macro I '(L x x))
;; helper macro: used twice in R and once in O
(defmacro w (S sf lf &optional(af sf))
`(if (symbolp ,S) ,sf
(destructuring-bind(a b &optional c) ,S
(if (eq a 'L)
,lf
,af))))
;; R : beta-reduction
(defun r (S &optional (N 97))
(w S
(symbol-value s)
(let ((v(make-symbol(make-string 1 :initial-element(code-char N)))))
(progv`(,b,v)`(,v,v)
`(L ,v ,(r c (1+ n)))))
(let ((F (r a N))
(U (r b N)))
(w F`(,F,U)(progv`(,b)`(,U)(r c N))))))
;; P : parse from stream to lambda tree
(defun p (&optional (stream *standard-output*))
(loop for c = (read-char stream nil #\))
until (eql c #\))
for q = (case c (#\S S) (#\K K) (#\I I) (#\( (p stream)))
for u = q then `(,u ,q)
finally (return u)))
;; O : output lambda forms as strings
(defun o (S)
(w S
(princ-to-string S)
(format nil "~A.~A" b (o c))
(format nil (w b "(~A~A)" "(~A(~A))") (o a) (o b))))
Beta-azaltma
Değişkenler, azaltma sırasında PROGV
yeni Common Lisp sembollerine göre dinamik olarak bağlanır MAKE-SYMBOL
. Bu çarpışmaların isimlendirilmesinden hoş bir şekilde kaçınmayı sağlar (örneğin sınır değişkenlerinin istenmeyen gölgelenmesi). Kullanabilirdim GENSYM
, ancak semboller için kullanıcı dostu isimler kullanmak istiyoruz. Yani semboller gelen harflerle adlandırılır yüzden ahiç z(Söz izin verdiği şekilde). N
mevcut kapsamdaki bir sonraki harfin karakter kodunu gösterir ve 97, aka ile başlar a.
İşte R
( W
makro olmadan ) daha okunaklı bir sürümü :
(defun beta-reduce (S &optional (N 97))
(if (symbolp s)
(symbol-value s)
(if (eq (car s) 'L)
;; lambda
(let ((v (make-symbol (make-string 1 :initial-element (code-char N)))))
(progv (list (second s) v)(list v v)
`(L ,v ,(beta-reduce (third s) (1+ n)))))
(let ((fn (beta-reduce (first s) N))
(arg (beta-reduce (second s) N)))
(if (and(consp fn)(eq'L(car fn)))
(progv (list (second fn)) (list arg)
(beta-reduce (third fn) N))
`(,fn ,arg))))))
Orta sonuç
Dizeden ayrıştır:
CL-USER> (p (make-string-input-stream "K(K(K(KK)))"))
((L X (L U X)) ((L X (L U X)) ((L X (L U X)) ((L X (L U X)) (L X (L U X))))))
azaltın:
CL-USER> (r *)
(L #:|a| (L #:|a| (L #:|a| (L #:|a| (L #:|a| (L #:|b| #:|a|))))))
(İcra izine bakınız)
Pretty-print:
CL-USER> (o *)
"a.a.a.a.a.b.a"
Testler
Python cevabıyla aynı test takımını tekrar kullanıyorum:
Input Output Python output (for comparison)
1. KSK a.b.c.a(c)(b(c)) a.b.c.a(c)(b(c))
2. SII a.a(a) a.a(a)
3. S(K(SI))K a.b.b(a) a.b.b(a)
4. S(S(KS)K)I a.b.a(a(b)) a.b.a(a(b))
5. S(S(KS)K)(S(S(KS)K)I) a.b.a(a(a(b))) a.b.a(a(a(b)))
6. K(K(K(KK))) a.a.a.a.a.b.a a.b.c.d.e.f.e
7. SII(SII) ERROR ERROR
8. test örneği, yukarıdaki tablo için çok büyük:
8. SS(SS)(SS)
CL a.b.a(b)(c.b(c)(a(b)(c)))(a(b.a(b)(c.b(c)(a(b)(c))))(b))
Python a.b.a(b)(c.b(c)(a(b)(c)))(a(d.a(d)(e.d(e)(a(d)(e))))(b))
- DÜZENLEME ile aynı gruplama davranışına sahip olmak için cevabımı güncelledim. Aditsu'nun cevabında , çünkü yazmak daha az byte'a mal oldu.
- Kalan fark sonucu testler 6 ve 8 için görülebilir
a.a.a.a.a.b.a
doğru olduğunu ve bağlamaları için Python cevap olarak çok harflerle gibi kullanmaz a
, b
, c
ve d
belirtilmemiştir.
performans
Yukarıdaki 7 geçiş testinin üzerinden geçerek sonuçları toplamak hemen gerçekleşir (SBCL çıkışı):
Evaluation took:
0.000 seconds of real time
0.000000 seconds of total run time (0.000000 user, 0.000000 system)
100.00% CPU
310,837 processor cycles
129,792 bytes consed
Aynı testi yüzlerce kez yapmak ... Özel değişkenlerle ilgili bilinen bir sınırlama nedeniyle, SBCL'de "Lokal yerel depolama bitmiştir" sonucunu veriyor . CCL ile aynı test takımının 10000 kez aranması 3.33 saniye sürer.