Λ-ifadelerini SK-ifadelerine dönüştürme


20

Λ-taşı veya lambda taşı, anonim fonksiyonlarına göre mantıksal bir sistemdir. Örneğin, bu bir λ ifadesi:

λf.(λx.xx)(λx.f(xx))

Ancak, bu zorluğun amaçları için gösterimi basitleştireceğiz:

  • Değişim λiçin \(daha kolay yazmak için yapmak):\f.(\x.xx)(\x.f(xx))
  • .Biz bırakın böylece lambda başlıklarda, gereksiz:\f(\xxx)(\xf(xx))
  • İki işlevi birlikte yazmak yerine uygulama için Unlambda stili önek gösterimini kullanın `(bunun nasıl yapılacağına dair tam bir açıklama için bkz. Lambda Matematik Gösterimleri arasında dönüştürme ):\f`\x`xx\x`f`xx
  • Bu en karmaşık ikamedir. Her değişkeni, değişkenin ait olduğu lambda başlığına göre ne kadar derinden yuvalandığına bağlı olarak parantez içindeki bir sayıyla değiştirin (yani 0 tabanlı De Bruijn dizinini kullanın ). Örneğin, \xx(kimlik fonksiyonu) ' xnda, gövde içindeki ile değiştirilir [0], çünkü ifade değişkenden sonuna doğru giderken karşılaşılan ilk (0 tabanlı) başlığa aittir; \x\y``\x`xxxydönüştürülür \x\y``\x`[0][0][1][0]. Şimdi değişkenleri başlıklara bırakabiliriz \\``\`[0][0][1][0].

Kombinatorik mantık temel olarak λ-hesabından yapılmış bir Turing Tarpit'tir (Aslında, önce geldi, ancak bu ilgisiz.)

"Kombine edici mantık, lambda hesabının bir varyantı olarak görülebilir, burada lambda ifadeleri (fonksiyonel soyutlamayı temsil eden), bağlı değişkenlerin bulunmadığı ilkel işlevlerin sınırlı bir birleştirici kümesiyle değiştirilir." 1

En yaygın birleştirici mantık türü , aşağıdaki ilkelleri kullanan SK birleştirici hesabıdır :

K = λx.λy.x
S = λx.λy.λz.xz(yz)

Bazen bir birleştirici I = λx.xeklenir, ancak SKK(veya SKxherhangi xbiri için ) eşdeğer olduğu için gereksizdir I.

Λ hesabında herhangi bir ifadeyi kodlayabilmek için tek ihtiyacınız olan K, S ve uygulama. Örnek olarak, işlevden λf.(λx.xx)(λx.f(xx))birleştirici mantığa bir çeviri :

λf.(λx.xx)(λx.f(xx)) = S(K(λx.xx))(λf.λx.f(xx))
λx.f(xx) = S(Kf)(S(SKK)(SKK))
λf.λx.f(xx) = λf.S(Kf)(S(SKK)(SKK))
λf.S(Sf)(S(SKK)(SKK)) = S(λf.S(Sf))(K(S(SKK)(SKK)))
λf.S(Sf) = S(KS)S
λf.λx.f(xx) = S(S(KS)S)(K(S(SKK)(SKK)))
λx.xx = S(SKK)(SKK)
λf.(λx.xx)(λx.f(xx)) = S(K(S(SKK)(SKK)))(S(S(KS)S)(K(S(SKK)(SKK))))

Önek notasyonunu kullandığımız için, bu ```S`K``S``SKK``SKK``S``S`KSS`K``SKK`.

1 Kaynak: Wikipedia

Meydan okuma

Şimdiye kadar, muhtemelen ne olduğunu tahmin ettiniz: SK-birleştirici hesabında yeniden yazılan geçerli bir λ ifadesi (yukarıda açıklanan gösterimde) giriş ve çıkışlar (veya döndürür) olarak aynı işlevi alan bir program yazın. Bunu yeniden yazmanın sonsuz sayıda yolu olduğunu unutmayın; sadece sonsuz yollardan birini çıkarmanız gerekir.

Bu , bu nedenle (bayt cinsinden ölçülen) en kısa geçerli gönderim kazanır.

Test Durumları

Her test durumu bir olası çıktı gösterir. Üstteki ifade eşdeğer λ-kalkülüs ifadesidir.

λx.x:
\[0]                        -> ``SKK
λx.xx:
\`[0][0]                    -> ```SKK``SKK
λx.λy.y:
\\[0]                       -> `SK
λx.λy.x:
\\[1]                       -> K
λx.λy.λz.xz(yz):
\\\``[2][0]`[1][0]          -> S
λw.w(λx.λy.λz.xz(yz))(λx.λy.x):
\``[0]\\[1]\\\``[2][0]`[1][0] -> ``S``SI`KS`KK


1
Sanırım ikinci test durumunuz doğru değil. Sonuncusu parantez içinde olmayan bir sayı içerir.
Christian Sievers


Nasıl buldun λx.f(xx) = S(Kf)(SKK)? Olmamalı mıydı λx.f(xx) = S(Kf)(SII) = S(Kf)(S(SKK)(SKK))? Dönüştürürken λx.f(xx), S {λx.f} {λx.xx}hangi azaltıldığını alıyorum S (Kf) {λx.xx}ve parantez içindeki ifade ω=λx.xx, bildiğimizden başka bir şey değil SII = S(SKK)(SKK), değil mi?
BarbaraKwarc

@BarbaraKwarc Doğru, demek istedim SII, değil SKK. O bir hataydı.
Esolanging Fruit

Yanıtlar:


9

Haskell, 251237222214 bayt

@ Ørjan_Johansen sayesinde 15 bayt tasarruf etti (açıklamalarında TIO bağlantılarına da bakın)!

@Nimi sayesinde 8 bayt daha kaydedildi!

data E=S|K|E:>E|V Int
p(h:s)|h>'_',(u,a)<-p s,(v,b)<-p u=(v,a:>b)|h>'['=a<$>p s|[(n,_:t)]<-reads s=(t,V n)
a(e:>f)=S:>a e:>a f
a(V 0)=S:>K:>K
a(V n)=K:>V(n-1)
a x=K:>x
o(e:>f)='`':o e++o f
o S="S"
o K="K"
f=o.snd.p

pgirdiyi ayrıştırır ve sonuçta elde edilen çiftin ilk bileşeninde kalan ayrıştırılmamış kısmı döndürür. Argümanın ilk karakteri bir ters çentik, bir ters eğik çizgi veya bir açılış parantezi olmalıdır. Desen korumaları pbu durumları bu sırayla kontrol eder. İlk durumda, bir uygulamayı ifade ederek, iki ifade daha ayrıştırılır ve Einfix yapıcısı ile veri tipindeki bir elemanla birleştirilir :>. Lambda durumunda, aşağıdaki ifade ayrıştırılır ve hemen aişleve verilir . Aksi takdirde, bir değişkendir, readsişlevini (bir liste döndürür) işleviyle alır ve desen eşleştirmesi ile kapanış parantezini bırakırız (_:t).

aFonksiyon oldukça iyi bilinen braket soyutlama yapar. Bir uygulamayı özetlemek için, iki alt ifadeyi özetliyoruz ve Sargümanı her ikisine de dağıtmak için birleştiriciyi kullanıyoruz . Bu her zaman doğrudur, ancak daha fazla kodla daha kısa ifadeler almak için özel durumları ele alarak daha iyisini yapabiliriz . Akım değişkeninin soyutlanması Iveya buna sahip olmadığımızda SKK. Genellikle geri kalan durumlar sadece öne ekleyebilir K, ancak bu gösterimi kullanırken, iç lambda soyutlandığı için değişkenleri yeniden numaralandırmamız gerekir.

o sonucu çıktı için bir dizgiye dönüştürür. ftam işlevidir.

Birçok dilde olduğu gibi, ters eğik çizgi bir kaçış karakteri olduğundan, bir dizgi değişmezinde iki kez verilmelidir:

*Main> f "\\[0]"
"``SKK"
*Main> f "\\`[0][0]"
"``S``SKK``SKK"
*Main> f "\\\\[0]"
"``S``S`KS`KK`KK"
*Main> f "\\\\[1]"
"``S`KK``SKK"
*Main> f "\\\\\\``[2][0]`[1][0]"
"``S``S`KS``S``S`KS``S`KK`KS``S``S`KS``S``S`KS``S`KK`KS``S``S`KS``S`KK`KK``S`KK``SKK``S``S`KS``S``S`KS``S`KK`KS``S`KK`KK``S`KK`KK``S``S`KS``S``S`KS``S`KK`KS``S``S`KS``S`KK`KK``S``S`KS`KK`KK``S``S`KS``S``S`KS``S`KK`KS``S`KK`KK``S`KK`KK"

1
1. İkinci satırda kullanabilirsiniz (a,(b,v))<-p<$>p s. 2. '\\'Sadece olabilir _son o maçı taşırsanız.
Ørjan Johansen

1
Aslında, ilk kısmı çizin: Demet sırasını değiştirmek p(_:s)=a<$>p sve (taşınan) '\\'çizgi için kullanmak daha kısadır .
Ørjan Johansen

1
Çevrimiçi deneyin! mevcut sürümünüz için. Bu arada sadece 236 bayt olan son satır sonunu bırakabilirsiniz.
Ørjan Johansen

2
@ Challenger5 Bence bu çoğunlukla haskell'in lambda hesabına dayalı olmasından kaynaklanıyor, bu yüzden haskell konusunda yetkin insanların bu tür sorulara çekilmesi daha muhtemel :)
Leo

2
Sen tanımlayabilirsiniz p, üç korumaları ile tek bir ifade ile vakaları yeniden düzenlemek ve bir gereksiz çifti damla (): p(h:s)|h>'_',(u,a)<-p s,(v,b)<-p u=(v,a:>b)|h>'['=a<$>p s|[(n,_:t)]<-reads s=(t,V n).
nimi
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.