(~!)(!)((~)~*):((!)~^)*(:^)(~(!)~^(~)~*)(()~(~)~^~*)
Essayez-le en ligne! (comprend une suite de tests et un texte identifiant des parties du programme)
Cela marque étonnamment bien pour un esolang de très bas niveau. (Les chiffres, les booléens, etc. de l’Église, sont très couramment utilisés dans Underload pour cette raison; la langue n’a pas de chiffres et de booléens intégrés, et c’est l’un des moyens les plus faciles de les simuler. Cela dit, il est également commun à coder les booléens en chiffres 0 et 1)
Pour ceux qui sont confus: Underload vous permet de définir des fonctions réutilisables, mais ne vous permet pas de les nommer de la manière habituelle, ils flottent simplement sur la pile d'arguments (donc si vous définissez cinq fonctions et souhaitez ensuite appeler la première) vous avez défini, vous devez écrire une nouvelle fonction qui prend cinq arguments et appelle le cinquième d’entre eux, puis l’appeler avec un nombre insuffisant d’arguments pour qu’elle recherche les arguments de réserve à utiliser). Les appeler les détruit par défaut, mais vous pouvez modifier l'appel pour le rendre non destructif (dans les cas simples, il suffit d'ajouter deux points à l'appel, bien que les cas complexes soient plus courants, car vous devez vous assurer que les copies sur la pile ne vous gênez pas), le support de fonction de Underload a donc toutes les exigences de la question.
Explication
vrai
(~!)
( ) Define function:
~ Swap arguments
! Delete new first argument (original second argument)
Celui-ci est assez simple; nous nous débarrassons de l'argument que nous ne voulons pas et l'argument que nous voulons ne fait que subsister, servant de valeur de retour.
faux
(!)
( ) Define function:
! Delete first argument
Celui-ci est encore plus simple.
ne pas
((~)~*)
( ) Define function:
~* Modify first argument by pre-composing it with:
(~) Swap arguments
Celui-ci est amusant: not
n'appelle pas son argument du tout, il utilise simplement une composition de fonction. C'est une astuce courante dans Underload, dans laquelle vous n'inspectez pas vos données, vous changez simplement la façon dont elles fonctionnent, en pré-et post-composant des éléments avec. Dans ce cas, nous modifions la fonction pour échanger ses arguments avant l'exécution, ce qui annule clairement un chiffre d'église.
et
:((!)~^)*
( ) 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
La question permet de définir des fonctions en fonction d'autres fonctions. Nous définissons "et" ensuite parce que plus récemment "non" a été défini, plus il est facile de l’utiliser. (Cela ne soustrait pas de notre partition, parce que nous ne nommons pas du tout "non", mais cela économise des octets au lieu de réécrire la définition. C’est le seul moment où une fonction se réfère à une autre, car faisant référence à une fonction mais la dernière définition coûterait trop d'octets.)
La définition ici est and x y = (not x) false y
. En d'autres termes, si not x
, alors nous revenons false
; sinon, nous revenons y
.
ou
(:^)
( ) Define function:
: Copy the first argument
^ Execute the copy, with arguments
{implicitly, the original first argument}
{and implicitly, our second argument}
@Nitrodon a souligné dans les commentaires qu'il or x y = x x y
est normalement plus court que or x y = x true y
, et que cela s'avère également correct en sous-charge. Une mise en œuvre naïve de ce principe serait (:~^)
, mais nous pouvons utiliser un octet supplémentaire en notant que peu importe que nous utilisions le premier argument original ou sa copie, le résultat est le même dans les deux cas.
La sous-charge ne prend pas réellement en charge le currying au sens habituel du terme, mais des définitions comme celle-ci lui donnent l’impression! (Le truc, c’est que les arguments non consommés restent collés, donc la fonction que vous appelez les interprétera comme ses propres arguments.)
implique
(~(!)~^(~)~*)
( ) Define function:
~ Swap arguments
~^ Execute the new first (original second) argument, with argument:
(!) false
{and implicitly, our second argument}
(~)~* Run "not" on the result
La définition utilisée ici est implies x y = not (y false x)
. Si y est vrai, cela se simplifie not false
, c'est- à -dire true
. Si y est faux, cela se simplifie not x
, nous donnant ainsi la table de vérité que nous voulons.
Dans ce cas, nous utilisons à not
nouveau, cette fois en réécrivant son code plutôt que de le référencer. C'est juste écrit directement comme (~)~*
sans parenthèses, donc il est appelé plutôt que défini.
xor
(()~(~)~^~*)
( ) Define function:
~ ~^ Execute the first argument, with arguments:
(~) "swap arguments"
() identity function
~* Precompose the second argument with {the result}
Cette fois-ci, nous n'évaluons qu'un seul de nos deux arguments et nous l'utilisons pour déterminer la composition du second argument. Underload vous permet de jouer rapidement et sans effort avec l'arité. Nous utilisons donc le premier argument pour choisir entre deux fonctions à deux arguments et deux retours; l'argument swap qui les renvoie tous les deux mais dans l'ordre inverse et la fonction d'identité qui les renvoie tous les deux dans le même ordre.
Lorsque le premier argument est vrai, nous produisons donc une version modifiée du deuxième argument qui permute ses arguments avant de s'exécuter, c'est-à-dire précompose avec "arguments de permutation", c'est-à-dire not
. Donc, un vrai premier argument signifie que nous retournons not
le deuxième argument. Par contre, un premier argument faux signifie que nous composons avec la fonction identité, c'est-à-dire que nous ne faisons rien. Le résultat est une implémentation de xor
.