(~!)(!)((~)~*):((!)~^)*(:^)(~(!)~^(~)~*)(()~(~)~^~*)
Probieren Sie es online! (enthält eine Testsuite und einen Text, der Teile des Programms identifiziert)
Dies ist überraschend gut für einen sehr niedrigen Esolang. (Church-Zahlen, Church-Boolesche Werte usw. werden in Underload aus diesem Grund sehr häufig verwendet. In der Sprache sind keine Zahlen und Boolesche Werte integriert, und dies ist eine der einfacheren Möglichkeiten, sie zu simulieren. Dies gilt auch für Kodieren Sie Boolesche Werte mit den Ziffern 0 und 1.)
Für alle, die verwirrt sind: Unter Last können Sie wiederverwendbare Funktionen definieren, aber nicht wie gewohnt benennen. Sie schweben einfach auf dem Argumentenstapel herum (wenn Sie also fünf Funktionen definieren und dann die erste aufrufen möchten) Sie haben definiert, dass Sie eine neue Funktion schreiben müssen, die fünf Argumente akzeptiert und das fünfte von ihnen aufruft. Rufen Sie sie dann mit unzureichend vielen Argumenten auf, damit sie nach zu verwendenden Ersatzargumenten sucht. Wenn Sie sie aufrufen, werden sie standardmäßig zerstört, aber Sie können den Aufruf so ändern, dass er nicht destruktiv ist (in einfachen Fällen müssen Sie dem Aufruf nur einen Doppelpunkt hinzufügen, obwohl die komplexen Fälle häufiger vorkommen, da Sie sicherstellen müssen, dass die Kopien vorhanden sind auf dem Stack nicht stören), so dass die Funktionsunterstützung von Underload alle Anforderungen hat, die wir aus der Frage heraus benötigen würden.
Erläuterung
wahr
(~!)
( ) Define function:
~ Swap arguments
! Delete new first argument (original second argument)
Das ist ziemlich einfach; Wir werden das Argument los, das wir nicht wollen, und das Argument, das wir wollen, bleibt einfach da und dient als Rückgabewert.
falsch
(!)
( ) Define function:
! Delete first argument
Das ist noch einfacher.
nicht
((~)~*)
( ) Define function:
~* Modify first argument by pre-composing it with:
(~) Swap arguments
Das macht Spaß: not
Nennt das Argument überhaupt nicht, sondern verwendet nur eine Funktionskomposition. Dies ist ein allgemeiner Trick in Underload, bei dem Sie Ihre Daten überhaupt nicht überprüfen, sondern lediglich die Funktionsweise ändern, indem Sie die Dinge vor und nach dem Komponieren damit bearbeiten. In diesem Fall ändern wir die Funktion, um ihre Argumente vor der Ausführung auszutauschen, wodurch eine Kirchennummer eindeutig negiert wird.
und
:((!)~^)*
( ) Define function:
~^ Execute its first argument with:
(!) false
{and implicitly, our second argument}
* Edit the newly defined function by pre-composing it with:
: {the most recently defined function}, without destroying it
Die Frage erlaubt die Definition von Funktionen in Bezug auf andere Funktionen. Wir definieren "und" als nächstes, weil es umso einfacher ist, es zu verwenden, je neuer "nicht" definiert wurde. (Dies subtrahiert nicht von unserer Punktzahl, da wir überhaupt nicht "nicht" benennen, sondern es werden Bytes gespart, wenn die Definition erneut geschrieben wird. Dies ist das einzige Mal, dass eine Funktion auf eine andere verweist, da sie sich auf eine Funktion bezieht aber die zuletzt definierte würde zu viele Bytes kosten.)
Die Definition hier ist and x y = (not x) false y
. Mit anderen Worten, wenn not x
, dann kehren wir zurück false
. ansonsten kehren wir zurück y
.
oder
(:^)
( ) Define function:
: Copy the first argument
^ Execute the copy, with arguments
{implicitly, the original first argument}
{and implicitly, our second argument}
@Nitrodon hat in den Kommentaren darauf hingewiesen, dass dies or x y = x x y
normalerweise kürzer ist als or x y = x true y
und dass es sich auch bei Unterlast als richtig herausstellt. Eine naive Umsetzung wäre das(:~^)
, aber wir können ein zusätzliches Byte herausholen, indem wir feststellen, dass es egal ist, ob wir das ursprüngliche erste Argument oder die Kopie davon ausführen, das Ergebnis ist in beiden Fällen dasselbe.
Unterlast unterstützt eigentlich nicht das Curry im üblichen Sinne, aber Definitionen wie diese lassen es so aussehen wie es ist! (Der Trick besteht darin, dass nicht konsumierte Argumente einfach herumstehen und von der aufgerufenen Funktion als eigene Argumente interpretiert werden.)
impliziert
(~(!)~^(~)~*)
( ) Define function:
~ Swap arguments
~^ Execute the new first (original second) argument, with argument:
(!) false
{and implicitly, our second argument}
(~)~* Run "not" on the result
Die hier verwendete Definition ist implies x y = not (y false x)
. Wenn y wahr ist, vereinfacht sich dies zu not false
, dh true
. Wenn y falsch ist, vereinfacht sich dies not x
und gibt uns die gewünschte Wahrheitstabelle.
In diesem Fall verwenden wir not
dieses Mal erneut, indem wir den Code neu schreiben, anstatt ihn zu referenzieren. Es wird direkt geschrieben, (~)~*
ohne Klammern, es wird also eher aufgerufen als definiert.
xor
(()~(~)~^~*)
( ) Define function:
~ ~^ Execute the first argument, with arguments:
(~) "swap arguments"
() identity function
~* Precompose the second argument with {the result}
Dieses Mal werten wir nur eines unserer beiden Argumente aus und verwenden es, um zu bestimmen, woraus das zweite Argument bestehen soll. Mit Unterlast können Sie schnell und locker mit Arity spielen. Daher verwenden wir das erste Argument, um zwischen zwei Funktionen mit zwei Argumenten und zwei Rückgabewerten zu wählen. das Argument swap, das beide in umgekehrter Reihenfolge zurückgibt, und die Identitätsfunktion, die beide in derselben Reihenfolge zurückgibt.
Wenn das erste Argument wahr ist, erzeugen wir daher eine bearbeitete Version des zweiten Arguments, die ihre Argumente vor dem Ausführen austauscht, dh mit "Swap-Argumenten" vorkomponiert, dh not
. Ein wahres erstes Argument bedeutet also, dass wir not
das zweite Argument zurückgeben. Andererseits bedeutet ein falsches erstes Argument, dass wir mit der Identitätsfunktion komponieren, dh nichts tun. Das Ergebnis ist eine Implementierung von xor
.