SKI rachunek jest wariant rachunku lambda, która nie używać wyrażeń lambda. Zamiast tego używana jest tylko aplikacja i kombinatory S , K i I. W tym wyzwaniu Twoim zadaniem jest przetłumaczenie terminów SKI na terminy Lambda w postaci β normalnej .
Specyfikacja wejściowa
Dane wejściowe to termin SKI w następującej reprezentacji tekstowej. Możesz zdecydować się na opcjonalny końcowy znak nowej linii. Sygnał wejściowy składa się z postaci S
, K
, I
, (
i )
i spełnia następujące gramatyczne (w postaci ABNF) przy sterm
czym symbol start:
sterm = sterm combinator ; application
sterm = combinator ;
sterm = '(' sterm ')' ; grouping
combinator = 'S' | 'K' | 'I' ; primitives
Specyfikacja wyjściowa
Dane wyjściowe to termin lambda bez wolnych zmiennych w następującej reprezentacji tekstowej. Możesz zdecydować się na wydrukowanie opcjonalnego końcowego znaku nowej linii. Wyjście powinno spełniać następującą gramatykę w formie ABNF, lterm
będąc symbolem początkowym:
lterm = lterm operand ; application
lterm = ALPHA '.' lterm ; lambda
lterm = operand
operand = '(' lterm ')' ; grouping
operand = ALPHA ; variable (a letter)
Ograniczenia
Możesz założyć, że dane wejściowe mają postać β normalną. Możesz założyć, że postać normalna β wykorzystuje maksymalnie 26 różnych zmiennych. Możesz założyć, że zarówno dane wejściowe, jak i wyjściowe są reprezentowalne w 79 znakach.
Przykładowe dane wejściowe
Oto kilka przykładowych danych wejściowych. Wyjście jest jednym możliwym wyjściem dla danego wejścia.
input output
I a.a
SKK a.a
KSK a.b.c.ac(bc)
SII a.aa
Punktacja
Najkrótsze rozwiązanie w oktetach wygrywa. Częste luki są zabronione.
sterm
ilterm
stosować lewostronne skojarzenie, gdy brakuje nawiasów.SKI
jakoS(KI)
.Odpowiedzi:
Haskell , 232 bajty
Wypróbuj online!
Jak to działa
To jest inny frontser parsera do mojej odpowiedzi na „Napisz interpreter dla niepisanego rachunku lambda” , która również ma wersję bez golfisty z dokumentacją.
W skrócie,
Term = T (Char -> String)
to rodzaj wyrażeń rachunku lambda, które wiedzą, jak stosować się do innych wyrażeń (a :: Term -> Term -> Term
) i jak wyświetlać się jakoString
((%) :: Term -> Char -> String
), biorąc pod uwagę początkową świeżą zmienną jakoChar
. Możemy przekonwertować funkcję na warunkach na termin za pomocąl :: (Term -> Term) -> Term
, a ponieważ zastosowanie wynikowego terminu po prostu wywołuje funkcję (a (l f) == f
), warunki są automatycznie redukowane do normalnej postaci, gdy są wyświetlane.źródło
Rubinowy, 323 bajty
Nie mogę uwierzyć, że ten gówno w ogóle działa:
Używanie podstawienia wyrażenia regularnego do przeprowadzania redukcji β na surowych ciągach to niektóre rzeczy Tony-the-Pony. Niemniej jednak jego wynik wygląda poprawnie przynajmniej w przypadku łatwych przypadków testowych:
Oto sposób obsługi
K(K(K(KK)))
niektórych danych wyjściowych debugowania, co zajmuje około 7 sekund na moim laptopie, ponieważ rekurencja wyrażeń regularnych jest powolna . Możesz zobaczyć jego konwersję α w akcji!źródło
Python 2, 674
Uwaga: po
while 1:
3 linie są wcięte znakiem tabulacji.Jest to w zasadzie kod za http://ski.aditsu.net/ , przetłumaczony na python, znacznie uproszczony i mocno golfowy.
Odniesienie: (prawdopodobnie jest to mniej przydatne teraz, gdy kod jest skompresowany)
V = termin zmienny
A = termin stosowania
L = współczynnik lambda
c = licznik zmiennej
p = zamień zmienną na termin
r = zmniejsz
m = ostateczna numeracja zmiennej
u = zmienna numeracja zmiennej wewnętrznej (dla zduplikowanych terminów)
s = konwersja łańcucha
(parametr s = jaźń)
C = znak (-y) separatora dla konwersji łańcucha
I, K, S: kombinatory
E = parsowanie
Przykłady:
(ten ↑ jest oczekiwany, ponieważ
SII(SII)
jest nieredukowalny)Dzięki Mauris i Sp3000 za pomoc w zabiciu kilku bajtów :)
źródło
def m(a,b,c):return foo
sięm=lambda a,b,c:foo
nawet w klasy, co może zaoszczędzić wiele bajtów.a.b.c.a(c)(b(c))
jako prawidłowego wyrażenia lambda: co to jest(c)
?Common Lisp, 560 bajtów
„Wreszcie znalazłem zastosowanie
PROGV
”.Nie golfił
Zmniejszenie beta
Zmienne są dynamicznie powiązane podczas redukcji z
PROGV
nowymi symbolami Common Lisp, za pomocąMAKE-SYMBOL
. Pozwala to ładnie uniknąć kolizji nazewnictwa (np. Niepożądane cieniowanie powiązanych zmiennych). Mógłbym użyćGENSYM
, ale chcemy mieć przyjazne nazwy dla symboli. Dlatego symbole są nazywane literami od ado z(zgodnie z pytaniem).N
reprezentuje kod znakowy następnej dostępnej litery w bieżącym zakresie i zaczyna się od 97, aliasa .Oto bardziej czytelna wersja
R
(bezW
makra):Wyniki pośrednie
Analizuj z ciągu:
Redukować:
(Zobacz ślad wykonania)
Ładny druk:
Testy
Używam ponownie tego samego zestawu testów, co odpowiedź w języku Python:
Ósmy przykład testu jest zbyt duży dla powyższej tabeli:
a.a.a.a.a.b.a
jest prawidłowy i nie używa jako dużo listów jako odpowiedź Python, gdzie wiązanie doa
,b
,c
id
nie odwołuje.Wydajność
Zapętlanie 7 powyższych testów pozytywnych i zbieranie wyników jest natychmiastowe (wynik SBCL):
Wykonanie tego samego testu sto razy prowadzi do… „Wyczerpanie lokalnego magazynu wątków” na SBCL, ze względu na znane ograniczenie dotyczące zmiennych specjalnych. W przypadku CCL wywołanie tego samego zestawu testów 10000 razy zajmuje 3,33 sekundy.
źródło