Niedociążenie to półfunkcyjna tarpit oparty na stosie stworzony przez ais523 . Ostatnio próbowałem grać w golfa, ponieważ jest to zaskakująco elegancki język.
Jakie masz wskazówki dotyczące gry w golfa w Underload? (Jedna wskazówka na odpowiedź)
Niedociążenie to półfunkcyjna tarpit oparty na stosie stworzony przez ais523 . Ostatnio próbowałem grać w golfa, ponieważ jest to zaskakująco elegancki język.
Jakie masz wskazówki dotyczące gry w golfa w Underload? (Jedna wskazówka na odpowiedź)
Odpowiedzi:
*
dla wyjściaPonieważ można generować, pozostawiając ciąg znaków na stosie , przydatne może być gromadzenie ciągu przy użyciu, *
a nie przy użyciu S
. Powiedzmy, że Twoim wyzwaniem było „weź ciąg i dodaj spację”, sposobem na zrobienie tego z wyjściem byłoby:
S( )S
Z *
drugiej strony można to zrobić o jeden bajt krócej:
( )*
Problem polega na tym, że jeśli dane wyjściowe mają dużą kumulację, przetworzenie elementu wyjściowego na stosie może kosztować bajty.
Jeśli musisz często używać fragmentu kodu, warto przechowywać ten kod na stosie i od czasu do czasu powielać go i sprawdzać. Jak dotąd jest to zwykłe programowanie niedociążenia. Niestety, utrzymywanie wartości na stosie przez długi czas jest trudne i powoduje, że kod staje się gadatliwy, i to prawda, nawet jeśli wartość jest funkcją, a nie danymi. Sytuacja staje się znacznie gorsza, jeśli masz wiele funkcji, które trzeba wielokrotnie wykorzystywać.
W rodzaju większego programu, który mógłby skorzystać z kilku ponownie używanych funkcji, rozwiązaniem, którego można użyć, jest utworzenie jednej dużej funkcji, która może spełnić dowolny z ich celów w zależności od tego, jak się nazywa (na podstawie tego, co znajduje się pod nią na stosie, lub poprzez zastosowanie długich nazywając sekwencje niż tylko ^
; funkcja starannie napisany można odróżnić ^^
od ^:^
od ^*^
od ^~^
, co daje cztery odrębne, dość krótkie sekwencje). W tym „słowniku” możesz także przechowywać inne przydatne rzeczy, takie jak ciągi znaków, których używasz wiele razy. Pamiętaj, że jeśli często używasz słownika, sensowne może być uczynienie go rodzajem quine, odsuwanie kopii z powrotem na stos, aby nie trzeba było ręcznie kopiować:
aby móc z niego korzystać bez utraty możliwości korzystania z niego w przyszłości.
^!!!!^
stylem wyszukiwania (którego również użyłem w kilku innych przykładach na stronie, szczególnie w sekcji minimalizacji). Chociaż może to nie dać najkrótszego wyszukiwania.
Jako prosty przykład, najczęściej spotykaną implementacją wartości logicznych są !()
fałsz (tj. Liczba całkowita 0), a łańcuch zerowy dla wartości prawda (tj. Liczba całkowita 1), ale jeśli masz problem silnie oparty na logicznym XOR, może to spowodować więcej warto użyć ciągu zerowego dla false i ~
dla true (ten format danych można przekonwertować na dowolny inny format boolowski przy użyciu (false)~(true)~^!
i pozwala na bardzo zwięzłą implementację *
dla XOR.
Można pójść jeszcze dalej z tą ogólną zasadą i korzystać z funkcji, których program będzie potrzebował później w ramach wartości danych; oszczędza to konieczności przechowywania funkcji i danych osobno na stosie. Może to sprawić, że kontrola będzie bardziej myląca, ale podczas gry w golfa, łatwość utrzymania często musi zająć miejsce z tyłu, a przecież przecież przecież przecież przecież nie wystarczy.
(!)
i (~!)
dla booleanów, ale twoja droga wydaje się lepsza.
Funkcjonalnie czystym sposobem na zmniejszenie liczby Kościoła jest użycie poprzedniej funkcji rachunku lambda:
\n.n(\p.\z.z($(pT))(pT))(\z.z0[whatever you define the predecessor of 0 to be])
Gdzie 0 = \ x. \ Yy, T = \ x. \ Yx, a $ jest następcą.
Przepisz w niedociążeniu, to 28 bajtów:
(!())~(!())~(!:(:)~*(*)*~)~^!
To jest w porządku, ale możemy wykorzystać niektóre przydatne właściwości Underload, a mianowicie to :!
i ()*
zrobić , że nie ma operacji. Oznacza to, że dla wielu n
, :ⁿ!!()()*ⁿ
(gdy cⁿ
jest c
powtarzane n
razy), otrzymano N-1. Na przykład zrobienie tego dla Kościoła nr 3 daje to:
:::!!()()***
Usuwając pary no-op, otrzymujemy:
:*
Który jest 2.
Oto nowa i krótsza operacja poprzednika:
:(:)~^(!!()())*~(*)~^*
Jest to 7 bajtów krótszych.
(()~(:))~:(^!!())*~(*)~^**
nadal jest o 3 bajty krótsze.
Niedociążenie ma dwa stosy - stos ciągów i stos poleceń składających się na kod źródłowy. ^
Instrukcja Underload pozwala nam przenosić łańcuchy z pierwszego stosu na drugi. W ten sposób możemy zaoszczędzić wiele niepotrzebnych manipulacji stosami.
Załóżmy na przykład, że mamy (a)(b)(c)
na głównym stosie i chcielibyśmy (c)
połączyć dwa dolne elementy, ignorując , aby uzyskać (ab)(c)
. Naiwnym sposobem na to jest obrócenie stosu, aby uzyskać, (c)(a)(b)
a następnie połączyć się i zamienić z powrotem:
a~a~*~a*^*~
To jest złe. Używanie a~a~*~a*^
do obracania stosu w ten sposób jest niezwykle kosztowne i należy go unikać, gdy jest to możliwe. (c)
Zamiast tego można wstawić do przestrzeni programu cztery bajty krótsze:
a(*)~*^
Chodzi o to, aby wziąć instrukcje, które chcesz wykonać, a następnie dodać instrukcję, aby odepchnąć (c)
na końcu, a następnie ocenić wynik. Oznacza to, że nie musimy się martwić, (c)
dopóki nie skończymy.
(*)~a*^
, które moim zdaniem jest nieco łatwiejsze do skomponowania. Zasadniczo ~a*^
jest to dip
polecenie Joy.
eval
polecenie, nigdy wcześniej nie widziałem takiego języka.