Church Booleans


33

Boolesche Kirche

Ein Church-Boolescher Wert ist eine Funktion, die xfür wahr und yfür falsch zurückgibt, wobei xdas erste Argument für die Funktion und ydas zweite Argument für die Funktion ist. Aus diesen Funktionen können weitere Funktionen zusammengestellt werden, die die and not or xorund implieslogischen Operationen darstellen.

Herausforderung

Konstruieren Sie die Kirche booleans und and not or xorund impliesKirche Tore in einer Sprache Ihrer Wahl. and orund xorsollte zwei Funktionen übernehmen (die Boolesche Werte der Kirche darstellen) und eine Funktion zurückgeben (die einen anderen Booleschen Wert der Kirche darstellt). In gleicher Weise notsollte die Funktion invertiert werden, und das impliesGate sollte eine boolesche Logik ausführen, bei der das erste Argument impliesdas zweite ist.

Wertung

Die Gesamtlänge der gesamten Code erforderlich ist, um Kirche zu machen trueund falsein Ihrer Sprache und die and not or xorund impliesKirche Tore ohne die Namen der Funktion. (Zum Beispiel false=lambda x,y:yin Python wären das 13 Bytes). Sie können diese Namen später in Ihrem Code wiederverwenden, indem Sie 1 Byte für die Bytesumme dieses Gatters zählen.

Pseudocode-Beispiele:

Die von Ihnen erstellten Funktionen sollten später in Ihrem Code so aufgerufen werden können.

true(x, y) -> x
false(x, y) -> y
and(true, true)(x, y) -> x
and(true, false)(x, y) -> y
# ... etc

2
Müssen wir die Funktionseingaben (oder die nächsten Ersatzfunktionen) als Black-Box-Funktionen behandeln, oder können wir den Code darin überprüfen? Und müssen die Rückgabewerte der logischen Operationen dieselben Funktionen haben, wie sie zuvor als kirchliche Boolesche definiert wurden, oder können sie etwas anderes sein, das dasselbe tut?
Unrelated String

1
@ JonathanAllan Ich habe es so bearbeitet, dass es korrekt war. Die Eingabeaufforderung ist so, wie sie jetzt sein sollte.
Ryan Schaefer

2
Können wir Listen als Argumente (zB true([x, y]), and([true, true])([x, y]))?
ar4093

2
@ RyanSchaefer Ich denke, Sie sollten es sich überlegen, die Argumente in einer geordneten Liste anzuordnen, da man die Argumente am Anfang der Lösungen einfach umbrechen könnte. Ich denke nicht, dass das Erfordernis, das dies erfordert, irgendetwas bewirkt, um diese Herausforderung zu verbessern (in der Tat denke ich, dass es das interessante Golfpotential einschränkt). Natürlich ist dies nur meine Meinung und es ist in Ordnung, wenn Sie nicht einverstanden sind.
FryAmTheEggman

1
Die Wertung ist eher verwirrend. Wäre es nicht besser, die Leute anonyme Funktionen einreichen zu lassen, aber wenn sie sie in anderen Teilen verwenden, müssen sie sie wie üblich zuweisen
Jo King,

Antworten:


14

Binäre Lambda- Rechnung , 13,875 - 12,875 Byte (103 Bit)

Binary Lambda Calculus Language (BLC) von John Tromp ist im Grunde ein effizientes Serialisierungsformat für Lambda-Kalkül. Es passt hervorragend zu dieser Aufgabe, da die Notation der Kirche sogar die "idiomatische" Art ist, mit Booleschen in BLC zu arbeiten.

Ich habe die folgenden Lambda-Funktionen für die Kombinatoren verwendet, von denen ich einige aus der Haskell-Antwort kopiert und golfen habe:, die durch eine erschöpfende Suche mit einer Beweisgrenze von 20 β-Reduktionen für jeden Fall gefunden wurden. Es besteht eine gute Chance, dass dies der kürzeste Weg ist.

True:  (\a \b a)
False: (\a \b b)
Not:   (\a \b \c a c b)
And:   (\a \b b a b)
Or:    (\a a a)
Xor:   (\a \b b (a (\c \d d) b) a)
Impl:  (\a \b a b (\c \d c))

Diese übersetzen in die folgenden (binären) BLC-Codesequenzen:

 bits |  name | BLC
------+-------+---------
    7 | True  | 0000 110
    6 | False | 0000 10
   19 | Not   | 0000 0001 0111 1010 110
   15 | And   | 0000 0101 1011 010
    8 | Or    | 0001 1010
   28 | Xor   | 0000 0101 1001 0111 0000 0101 0110
   20 | Impl  | 0000 0101 1101 0000 0110

Die obigen Funktionen sind insgesamt 111 Bits lang (13,875 Bytes) und 103 Bits lang (12,875 Bytes). Sie müssen nicht an Byte-Grenzen ausgerichtet sein, um in einem Programm verwendet zu werden. Daher ist es sinnvoll, gebrochene Bytes zu zählen.

Es gibt keine Wiederverwendung von Code zwischen den Kombinatoren, da es in BLC keine Variablen / Referenzen / Namen gibt - alles musste kopiert werden. Die Effizienz der Codierung sorgt jedoch für eine recht knappe Darstellung.


1
Ich weiß nicht, BLC, aber wird And: (\a \b a b a)funktionieren?
Dienstag,

Ja es funktioniert. Ich habe diese Formel tatsächlich für meine Codesequenzen verwendet. Ich habe nur vergessen, die entsprechende Lambda-Funktion zu aktualisieren (jetzt korrigiert). Die äquivalente Funktion arbeitet für Or: \a \b a a b. Es ist jedoch länger als das, was ich in BLC verwendet habe.
Pavel Potoček

25

Haskell , 50 - 6 = 44 Bytes

-1 Byte dank Khuldraeseth na'Barya und -1 Byte dank Christian Sievers.

t=const
f=n t
n=flip
a=n n f
o=($t)
x=(n>>=)
i=o.n

Probieren Sie es online!


2
Randnotiz: Sie können ShowInstanzen für constund definieren const idund die Booleschen Werte der Kirche direkt drucken. Probieren Sie es online! .
nimi


4
Warum benutzt niemand f=n t?
Christian Sievers

3
Sie können ein Byte speichern, indem Sie t=pureanstelle von verwenden t=const.
Joseph Sible

4
@JosephSible Das habe ich anfangs versucht. Leider t=puretritt ein Fehler auf, wenn ich versuche zu beantragen a, o, x, oder , ium es. Die Angabe der Art der tFehlerbehebung kostet mehr Byte als nur die Verwendung t=const.
Nitrodon

9

Python 2 (-3?)  101  95 Bytes

David Beazley frisst dein Herz raus!

-6 danke an Chas Brown (verschob die wiederholte :in den Join-Text>. <)

exec'=lambda x,y=0:'.join('F y;T x;N x(F,T);A x(y,F);O x(T,y);X x(N(y),y);I O(y,N(x))'.split())

Probieren Sie es online!

Ich denke , es könnte sein , 95 - 3weil ich die Funktionen nicht wiederverwendet werden A, Xoder I, aber ich benutze eine einzige =für die Zuweisung (vor lambda). Vielleicht kann ich keine entfernen; vielleicht bekomme ich ja 3.5 zu entfernen?


@ Ryan Schaefer kann ich drei entfernen oder kann ich meine Verwendung von execnicht? Ich sehe, dass es in beide Richtungen geht - ich verwende A, X oder I nicht wieder, aber der Code funktioniert ohne sie nicht. (Vielleicht kann ich sogar 3.5 entfernen ?!)
Jonathan Allan


Vielen Dank @Chas! Der Doppelpunkt, der durch das Netz rutschte :) Gute Arbeit auf dem Ersatz für -1 BTW
Jonathan Allan

7

JavaScript (Node.js) , 92 86 83 - 7 = 76 Byte

t=p=>q=>p
f=t(q=>q)
n=p=>p(f)(t)
a=p=>n(p)(f)
o=p=>p(t)
x=p=>p(n)(f())
i=p=>n(p)(t)

Probieren Sie es online! Link enthält grundlegende Testfälle. Bearbeiten: 6 9 Bytes dank @tsh gespeichert.


1
scheint man dies nicht behaupten kann , als -7 da t, f, nverwendet.
tsh

1
@tsh So verstehe ich das Punktesystem nicht. Der Name in der Definition wird explizit ausgeschlossen, obwohl der Name in der Verwendung 1 Byte kostet.
Neil

@Neil Sie können nicht den Byte - Rabatt für Funktionsnamen gekennzeichnet , die von Ihrem Code aufgerufen werden ( t, f, und nin Ihrem Fall).
Asgallant

2
@asgallant Nr. Es gibt keine Bytes für den Namen und 1 Byte, wenn es später verwendet wird. 'T fnaox i' sind keine Bytes mehr als 1 Byte, wenn sie später verwendet werden. Ich wollte die Lesbarkeit verbessern, aber jetzt ist mir klar, dass ich es einfach voll belassen sollte und es zu spät ist, es jetzt zu ändern
Ryan Schaefer,

@ RyanSchaefer wo ist diese Regel? Ich habe es noch nie so gesehen.
Asgallant

6

Python 2 , 133 - 6 = 127 94 Bytes

exec"t!u;f!v;n!u(f,t);a!u(v,f);o!u(t,v);x!u(n(v),v);i!o(v,n(u))".replace('!','=lambda u,v=0:')

Probieren Sie es online!

Schamlos die hinter Jonathan Allans Antwort verborgene Idee stehlen ; Es werden jedoch keine Bytes abgezogen.


Ich wollte eine Antwort auf meine eigene Frage posten, war mir aber nicht sicher, ob dies erlaubt war und ich denke, dass dies gegen den Geist davon ist. Also denke ich, ich werde dich stattdessen einfach weiterleiten. Gibt es überhaupt eine Möglichkeit, anstelle von Listen die Funktionen zu verwenden, die selbst eingegeben werden, und die spezielle Art und Weise, in der sie ihre Eingaben zurückgeben, um den Code zu verkürzen?
Ryan Schaefer

Ich wette, obwohl die Antwort ja lautet, würde es in Python erheblich länger dauern.
Unrelated String

Ich stehe korrigiert
Unrelated String

@ Mr.Xcoder du hast recht, ich hatte die falsche Anzahl von Bytes für die Beispielfunktion. Sie könnten jedoch 6 Bytes für die Namen der Funktionen entfernen.
Ryan Schaefer

@Herr. Xcoder: Nach Ihren Beobachtungen modifiziert.
Chas Brown

4

J , 67 Bytes - 7 = 60

t=.[
f=.]
n=.~
a=.2 :'u v]'
o=.2 :'[u v'
x=.2 :'u~v u'
i=.2 :'v u['

Probieren Sie es online!

Nichts wert:

Funktionen höherer Ordnung arbeiten in J anders als in einer funktionalen Sprache. Um ein neues Verb aus 1 oder 2 vorhandenen Verben zu erstellen, müssen Sie entweder ein Adverb (im Fall von 1) oder eine Konjunktion (im Fall von 2) verwenden.

Syntaktisch folgen Adverbien auf ein Verb, und Konjunktionen werden zwischen ihnen gesetzt. Also zu "nicht" einem Verb, das fdu tust f n, und zu "und" Verben fund gdir f a g.


4

Wolfram Language (Mathematica) , 61-7 = 54 Bytes

t=#&
f=#2&
a=#2~#~f&
o=t~#~#2&
n=f~#~t&
x=n@#~#2~#&
i=#2~#~t&

Probieren Sie es online!

ungegolft: inspiriert von Wikipedia ,

t[x_, y_] := x
f[x_, y_] := y
and[x_, y_] := x[y, f]
or[x_, y_] := x[t, y]
not[x_] := x[f, t]
xor[x_, y_] := y[not[x], x]
imply[x_, y_] := x[y, t]

Ziemlich sicher, dass die Zeilenumbrüche notwendig sind, um Funktionsdefinitionen zu trennen. Außerdem verweisen Sie in anderen Funktionsdefinitionen auf tf und n, damit Sie diese nicht abziehen können, also 61-4 = 57.
Jonathan Allan

@ JonathanAllan Ich habe die Scoring-Anweisungen erneut gelesen und bin damit einverstanden, dass die Zeilenumbrüche zählen sollten, danke. Ich bin mit Ihrem zweiten Teil nicht einverstanden: Wenn ich die Namen wieder verwende, zähle ich sie tatsächlich als "1 Byte für die Bytesumme dieses Gatters", was hier implizit ist, da ich 1-Byte-Namen verwende. Wie ich die Anweisungen gelesen habe, wird nicht erwähnt, dass sie weiterhin als ein Byte zur Gesamtsumme der ursprünglichen Definition gezählt werden. Also gehe ich mit N-7 Bytes. Ein weiterer Kommentar des OP verdeutlicht: "Es sind keine Bytes für den Namen und 1 Byte, wenn es später verwendet wird."
Roman

Ich habe "1 Byte später" gelesen, um zu verstehen, dass die Verwendung innerhalb einer anderen Funktion ein Byte kostet. Dies stimmt mit dem überein, was auch andere erzielt haben.
Jonathan Allan

@ JonathanAllan Ich bin weniger an Exegese interessiert und mehr an Code-Golf 😀
Roman

4

Unterlast , 56 52 Bytes

(~!)(!)((~)~*):((!)~^)*(:^)(~(!)~^(~)~*)(()~(~)~^~*)

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 ynormalerweise kürzer ist als or x y = x true yund 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 xund gibt uns die gewünschte Wahrheitstabelle.

In diesem Fall verwenden wir notdieses 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 notdas 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.


or x y = x x yspart einige Bytes über or x y = x true y.
Nitrodon

Unterlast ist häufig nicht intuitiv, wenn Literale durch wiederverwendete Variablen ersetzt werden sollen. In diesem Fall werden jedoch durch diese Umwandlung mehr Bytes als erwartet und nicht weniger gespeichert. Danke für die Verbesserung!
AIS523


3

Java 8, Score: 360 358 319 271 233 (240-7) Bytes

interface J<O>{O f(O x,O y,J...j);}J t=(x,y,j)->x;J f=(x,y,j)->y;J n=(x,y,j)->j[0].f(y,x);J a=(x,y,j)->j[0].f(j[1].f(x,y),y);J o=(x,y,j)->j[0].f(x,j[1].f(x,y));J x=(x,y,j)->j[0].f(j[1].f(y,x),j[1].f(x,y));J i=(x,y,j)->j[0].f(j[1].f(x,y),x);

Dies war schwieriger zu erreichen, als ich dachte, als ich damit anfing implies . Wie auch immer, es funktioniert .. Kann wahrscheinlich ein bisschen hier und da golfen werden. BEARBEITEN: Ok, Funktionen nicht wiederzuverwenden, sondern nur den gleichen Ansatz zu duplizieren, ist in Bezug auf die Byteanzahl für Java viel billiger. Und ich bekomme den vollen Bonus von -7, wenn ich keine der Funktionen ebenfalls benutze.

Probieren Sie es online aus.

Erläuterung:

// Create an interface J to create lambdas with 2 Object and 0 or more amount of optional
// (varargs) J lambda-interfaces, which returns an Object:
interface J<O>{O f(O x,O y,J...j);}

// True: with parameters `x` and `y`, always return `x`
J t=(x,y,j)->x;
// False: with parameters `x` and `y`, always return `y`
J f=(x,y,j)->y;

// Not: with parameters `x`, `y`, and `j` (either `t` or `f`), return: j(y, x)
J n=(x,y,j)->j[0].f(y,x);

// And: with parameters `x`, `y`, and two times `j` (either `t` or `f`), return:
//      j1(j2(x,y), y);
J a=(x,y,j)->j[0].f(j[1].f(x,y),y);

// Or: with parameters `x`, `y`, and two times `j` (either `t` or `f`), return:
//     j1(x, j2(x,y))
J o=(x,y,j)->j[0].f(x,j[1].f(x,y));

// Xor: with parameters `x`, `y`, and two times `j` (either `t` or `f`), return:
//      j1(j2(y,x), j2(x,y))
J x=(x,y,j)->j[0].f(j[1].f(y,x),j[1].f(x,y));

// Implies: with parameters `x`, `y`, and two times `j` (either `t` or `f`), return:
//          j1(j2(x,y), x)
J i=(x,y,j)->j[0].f(j[1].f(x,y),x);

2

C ++ 17, 207 - 49 = 158 195 - 58 = 137 Bytes

Die Zeilenumbrüche sind nicht erforderlich (außer den ersten beiden).

#define A auto
#define D(v,p)A v=[](A x,A y){return p;};
D(true_,x)
D(false_,y)
A not_=[](A f){return f(false_,true_);};
D(and_,x(y,false_))
D(or_,x(true_,y))
D(xor_,x(not_(y),y))
D(implies,x(y,true_))

Probieren Sie es online!

Unit-getestet mit Behauptungen wie:

static_assert('L' == true_('L', 'R'));
static_assert('R' == not_(true_)('L', 'R'));
static_assert('L' == and_(true_, true_)('L', 'R'));
static_assert('L' == or_(true_, true_)('L', 'R'));
static_assert('R' == xor_(true_, true_)('L', 'R'));
static_assert('L' == implies(true_, true_)('L', 'R'));

AKTUALISIERT: Früher hatte ich gehabt

A not_=[](A f){return[f](A x,A y){return f(y,x);};};

aber die Antwort von Roman wies den Weg zur kürzeren Version. Beachten Sie, dass jetzt not_(std::plus<>)schlecht geformt ist, wo es früher äquivalent war std::plus<>; aber da std::plus<>es keinen "Church Boolean" darstellt, denke ich, dass beide Verhaltensweisen den Regeln entsprechen.


Sollte "andere als die erste" nicht auf "andere als die ersten beiden" aktualisiert werden?
LF

@LF: Absolut richtig. Aktualisiert. :)
Quuxplusone

2

Forth (gforth) , 133 Bytes - 7 = 126 122

: j execute ;
: t drop ;
: f nip ;
: n ['] f ['] t rot j ;
: a dup j ;
: o over j ;
: x 2dup a n -rot o a ;
: m over n -rot a o ;

Probieren Sie es online!

-4 Bytes dank Quuxplusone

Anfangs habe ich dies deutlich überlegt, unter Berücksichtigung von Makros und Literalen, aber dann wurde mir klar, dass es viel einfacher wird, wenn ich Dinge in Bezug auf wahr und falsch definiere (wie ich es eigentlich hätte tun sollen).

Code Erklärung

\ Helper function to save some bytes
: j        \ define a new word
  execute  \ execute the word at the provided address
;          \ end word definition

\ True
: t        \ define a new word
  drop     \ drop the second argument
;          \ end the word

\ False
: f        \ define a new word
  nip      \ drop the first argument
;          \ end the word

\ Not - The "hardest" one because we have to reference true and false directly
: n        \ define a new word
  ['] f    \ get address of false
  ['] t    \ get the address of true
  rot      \ stick the input boolean back on the top of the stack
  j        \ call the input boolean, which will select the boolean to return
;          \ end the word

\ And 
: a        \ define a new word
  dup      \ duplicate the 2nd input value
  j        \ call the 2nd input on the first and second input
;          \ end the word

\ Or
: o        \ define a new word
  over     \ duplicate the 1st input value
  j        \ call the 1st input on the first and second input
;          \ end the word

\ Xor
: x        \ define a new word
  2dup     \ duplicate both of the inputs
  a n      \ call and, then not the result (nand)
  -rot     \ move the result behind the copied inputs
  o a      \ call or on the original inputs, then call and on the two results
;          \ end the word

\ Implies
: m        \ define a new word
  over     \ duplicate the 1st input value
  n        \ call not on the 1st input value
  -rot     \ move results below inputs
  a o      \ call and on the two inputs, then call or on the two results
;          \ end the word

1
Sie wiederholen das lange Wort executedreimal. Wenn Sie die Kurzschrift definieren : j execute ;, sparen Sie 4 Bytes.
Quuxplusone

1

SKI-Kalkül + C-Kombinator, 36 Bytes

true=K
false=SK
not=C
and=CC(SK)
or=CIK
xor=C(CIC)I
implies=CCK

Ich kenne eigentlich keinen Interpreter, mit dem Sie zusätzliche Kombinatoren in Bezug auf vorherige definieren können. Deshalb musste ich dies mit http://ski.aditsu.net/ testen, indem ich die gewünschten Kombinatoren, z. B. CCKK(SK)pqAusgaben q, einfügte , um dies zu zeigen Kimpliziert nicht SK.


1

Julia 1.0 , 36 Bytes

(b::Bool)(x,y)=b ? x : y;i(x,y)=!x|y

Ich weiß nicht, ob das zählt, ich überlade eigentlich nur den nativen BoolTyp, um aufrufbar zu sein, also bekomme ich die meisten Logikgatter kostenlos. impliesDa Julia leider kein Tor hat, musste ich meine eigene Funktion schreiben.

Probieren Sie es online!


Ich denke, Sie müssen die überladenen Operatoren immer noch in Ihre Einreichung einbeziehen ... aber die Wertung zählt sie nicht, da es sich nur um Namen handelt? Also wären es +6 Bytes von den Zeilenumbrüchen? Ich bin mir nicht sicher, wie die Wertung bei dieser Herausforderung funktioniert
Jo King,

Ich bin mir auch nicht hundertprozentig sicher, wie es funktioniert, aber wenn ich Code einfügen muss, der buchstäblich nichts bewirkt, ergibt das für mich keinen Sinn.
User3263164

Auch wenn der Code bereits deklariert ist, müssen Sie ihn dennoch einschließen, da sonst jede andere Einsendung der Golfsprache null Byte beträgt. Sie müssen es einfach keinem zuweisen
Jo King,


1

C ++ 17, 202 - 49 = 153 193 - 58 = 135 Bytes

Inspiriert von der Kommentardiskussion darüber, was ohnehin als 2-stellige Funktion gilt, hier ein Curry Version meiner vorherigen C ++ 17-Lösung. Es ist tatsächlich kürzer, weil wir das gleiche Makro zum Definieren verwenden können not_, um alle anderen Funktionen zu definieren!

#define D(v,p)auto v=[](auto x){return[=](auto y){return p;};};
D(true_,x)
D(false_,y)
D(not_,x(false_)(true_)(y))
D(and_,x(y)(false_))
D(or_,x(true_)(y))
D(xor_,x(not_(y))(y))
D(implies,x(y)(true_))

Probieren Sie es online!

Dieser wird mit Behauptungen wie getestet

static_assert('R' == and_(true_)(false_)('L')('R'));
static_assert('L' == or_(true_)(false_)('L')('R'));

Beachte das or_ als effektiv definiert ist

auto or_=[](auto x){return[=](auto y){return x(true_)(y);};};

Wir könnten definieren or_ "prägnanter" definieren als

auto or_=[](auto x){return x(true_);};

aber das würde uns kosten, weil wir das DMakro nicht mehr benutzen würden .


Wie wäre es mit der Verwendung von Trueund Falseanstelle von true_und, da C ++ zwischen Groß- und Kleinschreibung unterscheidet false_? Ähnliches gilt für die anderen Betreiber. Das spart 12 Bytes.
G. Sliepen

@ G.Sliepen: Der Bewertungsalgorithmus von OP berücksichtigt bereits, dass Bezeichner effektiv ein Zeichen lang sind. Zitat: "Die Gesamtlänge des gesamten Codes, der erforderlich ist, um Church in Ihrer Sprache als wahr und falsch zu kennzeichnen, und das und nicht oder x oder und impliziert Church-Gates ohne den Funktionsnamen. (Beispiel: false = lambda x, y: y in Python Sie können diese Namen später in Ihrem Code wiederverwenden , indem Sie 1 Byte für die Bytesumme dieses Gatters zählen. "
Quuxplusone

Ah, das habe ich verpasst.
G. Sliepen

0

APL (dzaima / APL) , 47 Byte SBCS

Beyogen auf Jonahs J-Lösung .

true und false sind Infix-Funktionen, notsind Suffix-Operatoren und der Rest sind Infix-Operatoren.

true←⊣
false←⊢
and←{⍺(⍶⍹false)⍵}
not←⍨
or←{⍺(true⍶⍹)⍵}
xor←{⍺(⍶not⍹⍶)⍵}
implies←{⍺(⍹⍶true)⍵}

Gemäß OP zählt dies alles von und bis zum Ende jeder Zeile und zählt jeden Aufruf einer vorherigen Definition als ein einzelnes Byte.

Probieren Sie es online!

wahr und falsch sind die linken und rechten Identitätsfunktionen.

not tauscht einfach die Argumente seiner Operandenfunktion aus.

Der Rest implementiert den Entscheidungsbaum:

andVerwendet die rechte Funktion , um das Ergebnis der linken Funktion auszuwählen, wenn true, andernfalls das Ergebnis der falseFunktion.

orVerwendet die Funktion für die linke Hand , um " truewenn wahr" auszuwählen , andernfalls das Ergebnis der Funktion für die rechte Hand .

xorVerwendet die rechte Funktion , um das negierte Ergebnis der linken Funktion auszuwählen, ⍶notwenn true, sonst das Ergebnis der linken Funktion.

impliesVerwendet die Funktion für die linke Hand , um das Ergebnis der Funktion für die rechte Hand auszuwählen, wenn dies wahr ist, andernfalls das Ergebnis der trueFunktion.


0

Stax , 34 Bytes

¿S£↓♣└²≡é♫Jíg░EèΩRΦ♂°┤rà╝¶πï╡^O|Θà

Führen Sie es aus und debuggen Sie es unter staxlang.xyz!

Schiebt eine Reihe von Blöcken auf den Stapel. Jeder Block erwartet sein letztes Argument auf dem Stapel, gefolgt von dem Rest in umgekehrter Reihenfolge.

Entpackt (41 Bytes):

{sd}Y{d}{y{d}a!}X{ya!}{b!}{cx!sa!}{sx!b!}

Jedes Paar { }ist ein Block. Ich benutzte die zwei Register X und Y, um sie zu halten trueund notso konnte ich später leicht auf sie zugreifen. Unglücklicherweise,false konnte es nicht einfach ein No-Op sein, da dies den Stapel überladen und einen einzelnen XOR-Fall durcheinander bringen würde.

Testsuite, kommentiert

false
{sd}    stack:   x y
 s      swap:    y x
  d     discard: y

true
{d}    stack:   x y
 d     discard: x

not
{y{d}a!}    stack:  p
 y{d}       push:   p f t
     a      rotate: f t p
      !     apply:  p(f,t)

and
{ya!}    stack:  p q
 y       push:   p q f
  a      rotate: q f p
   !     apply:  p(q,f)

or
{b!}    stack:  p q
 b      copies: p q p q
  !     apply:  p q(q,p)

xor
{cx!sa!}    stack:  p q
 c          copy:   p q q
  x!        not:    p q nq
    s       swap:   p nq q
     a      rotate: nq q p
      !     apply:  p(nq,q)

implies
{sx!b!}    stack:  p q
 s         swap:   q p
  x!       not:    q np
    b      copies: q np q np
     !     apply:  q np(np,q)

0

Befunge-98 , 105 77 65 Bytes

Weiter spielen mit dem Begriff "Funktion" in Sprachen ohne Funktionen ... hier ist eine Befunge-98-Version von Church Booleans!

In diesem eingeschränkten Dialekt von Befunge-98 besteht ein Programm aus einer Reihe von "Zeilen" oder "Funktionen", von denen jede mit einer >(Go Right) -Anweisung in Spalte x = 0 beginnt . Jede "Funktion" kann mit ihrer Zeilennummer (y-Koordinate) identifiziert werden. Funktionen können über Befunges Stack eingegeben werden wie gewohnt .

Zeile 0 ist etwas Besonderes, da (0,0) die Start-IP ist. Um ein Programm zu erstellen, das Zeile L ausführt, platzieren Sie einfach Anweisungen in Zeile 0, die, wenn sie ausgeführt werden, den Anweisungszeiger auf (x = L, y = 0) bewegen.

Die Magie geschieht in Zeile 1. Zeile 1 gibt bei der Ausführung eine Zahl aus L vom Stapel und springt zur Zeilennummer L. (Diese Zeile war zuvor eine > >>0{{2u2}2}$-073*-\x, die zu jeder Zeile "absolut springen" kann. Da ich jedoch weiß, dass diese Zeile an Zeile 1 gebunden ist, können wir L-1Zeilen in einer Menge weniger Code "relativ springen" .)

Zeile 2 steht für Kirche FALSE . Bei der Ausführung werden zwei Zahlen tund fvom Stapel abgerufen und dann zur Zeilennummer geflogen f.

Zeile 3 steht für Kirche TRUE . Wenn er ausgeführt wird , erscheint es zwei Zahlen tund faus dem Stapel und dann fliegt nach Zeilennummer t.

Linie 6, die die Kirche repräsentiert XOR, ist innovativ. Wenn es ausgeführt wird, werden zwei Zahlen aund bvom Stapel abgerufen und dann zur Zeile amit der Stapeleingabe geflogen NOT EXEC b. Wenn also adie Kirche repräsentiert TRUE, ist das Ergebnis des a NOT EXEC bWillens NOT b; und wenn arepräsentiert KircheFALSE , ist das Ergebnis des a NOT EXEC bWillens EXEC b.


Hier ist die ungolfed Version mit Testgeschirr. Richten Sie in Zeile 0 den Stack mit Ihrer Eingabe ein. Zum Beispiel 338bedeutet IMPLIES TRUE TRUE. Stellen Sie den Verschluss sicherx genau (x, y) = (0,15) ist, sonst funktioniert nichts! Stellen Sie außerdem sicher, dass Ihre Stapelkonfiguration mit beginnt ba, damit das Programm tatsächlich mit einer Ausgabe beendet wird.

Probieren Sie es online!

>  ba 334  0f-1x
> >>1-0a-\x             Line 1: EXEC(x)(...) = goto x
> $^< <            <    Line 2: FALSE(t)(f)(...) = EXEC(f)(...)
> \$^                   Line 3: TRUE(t)(f)(...) = EXEC(t)(...)
> 3\^                   Line 4: OR(x)(y)(...) = EXEC(x)(TRUE)(y)(...)
> 3\2\^                 Line 5: NOT(x)(...) = EXEC(x)(FALSE)(TRUE)(...)
> 1\5\^                 Line 6: XOR(x)(y)(...) = EXEC(x)(NOT)(EXEC)(...)
> 2>24{\1u\1u\03-u}^    Line 7: AND(x)(y)(...) = EXEC(x)(y)(FALSE)(...)
> 3^                    Line 8: IMPLIES(x)(y)(...) = EXEC(x)(y)(TRUE)(...)

> "EURT",,,,@
> "ESLAF",,,,,@

Hier ist die Version, deren Bytes ich gezählt habe.

>>>1-0a-\x
>$^<< }u-30\<
>\$^
>3\^\
>3\2^
>1\5^
>2>24{\1u\1u^
>3^

Beachten Sie, dass Sie zum Definieren einer Funktion in diesem Dialekt den Namen überhaupt nicht erwähnen. Sein "Name" wird durch seinen Ursprungsort bestimmt. Um eine Funktion aufzurufen, geben Sie ihren "Namen" an. Zum Beispiel wird XOR( 6) durch NOTund EXEC( 5und 1) definiert. Aber alle meine "Funktionsnamen" benötigen bereits nur ein Byte, um dargestellt zu werden. Diese Lösung erhält also keine Bewertungsanpassungen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.