Chiesa booleana


33

Chiesa booleana

Un booleano della Chiesa è una funzione che ritorna xper vero e yper falso dove xè il primo argomento della funzione ed yè il secondo argomento della funzione. Ulteriori funzioni possono essere composte da queste funzioni che rappresentano il and not or xoreimplies logiche operazioni.

Sfida

Costruire le booleani della Chiesa e and not or xore impliescancelli della Chiesa in una lingua di vostra scelta. and ore xordovrebbe assumere due funzioni (che rappresentano i booleani della Chiesa) e restituire una funzione (che rappresenta un altro booleano della Chiesa). Allo stesso modo, notdovrebbe invertire la funzione che assume e il impliesgate dovrebbe eseguire booleani implica la logica in cui il primo argomentoimplies il secondo.

punteggio

La lunghezza totale di tutto il codice richiesto per rendere Church truee falsenella tua lingua e le porte and not or xore impliesChurch esclusi il nome della funzione. (ad esempio, false=lambda x,y:yin Python sarebbero 13 byte). Puoi riutilizzare questi nomi in un secondo momento nel tuo codice, contando 1 byte per il totale byte di quel gate.

Esempi di pseudo-codice:

Le funzioni che crei dovrebbero poter essere chiamate in seguito nel tuo codice in questo modo.

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

2
Dobbiamo trattare gli input delle funzioni (o i sostituti più vicini) come funzioni black-box o possiamo ispezionare il codice all'interno? E i valori di ritorno delle operazioni logiche devono essere le stesse funzioni precedentemente definite come booleane della Chiesa, oppure possono essere qualcos'altro che fa la stessa cosa?
Corda non correlata

1
@JonathanAllan L'ho modificato in modo che fosse corretto. Il prompt è come dovrebbe essere ora.
Ryan Schaefer,

2
Possiamo prendere le liste come argomenti (ad esempio true([x, y]), and([true, true])([x, y]))?
ar4093,

2
@RyanSchaefer Penso che dovresti riconsiderare il fatto di consentire agli argomenti di essere in un elenco ordinato, in quanto si potrebbe semplicemente concludere gli argomenti all'inizio delle soluzioni. Non penso che richiedere ciò faccia qualcosa per migliorare questa sfida (in effetti penso che limiti il ​​potenziale di golf interessante). Certo, questa è solo la mia opinione, e va bene se non sei d'accordo.
FryAmTheEggman,

1
Il punteggio è piuttosto confuso. Non sarebbe meglio permettere alle persone di inviare funzioni anonime, ma se le usano in altre parti devono assegnarle, proprio come al solito
Jo King il

Risposte:


14

Calcolo lambda binario , 13.875 12.875 byte (103 bit)

Binary Lambda Calculus Language (BLC) di John Tromp è fondamentalmente un formato di serializzazione efficiente per il calcolo lambda. È perfetto per questo compito, poiché la notazione della Chiesa è persino il modo "idiomatico" di lavorare con i booleani in BLC.

Ho usato le seguenti funzioni lambda per i combinatori, alcune delle quali ho copiato e giocato dalla risposta di Haskell:, che sono state trovate da una ricerca esaustiva con un limite di prova di 20 β-riduzioni per ogni caso. Vi sono buone probabilità che siano le più brevi possibili.

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))

Questi si traducono nelle seguenti sequenze di codici BLC (binari):

 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

Le funzioni sopra sono lunghe in totale 111 bit (13.875 byte) 103 bit in lunghezza (12.875 byte). Non hanno bisogno di essere allineati ai confini dei byte per essere utilizzati all'interno di un programma, quindi ha senso contare i byte frazionari.

Non c'è riutilizzo del codice tra i combinatori, perché non ci sono variabili / riferimenti / nomi in BLC - tutto doveva essere copiato. Tuttavia, l'efficienza della codifica rende una rappresentazione piuttosto concisa.


1
Non conosco blc, ma And: (\a \b a b a)funzionerà?
TSH

Sì funziona. In realtà ho usato questa formula per le mie sequenze di codice. Ho appena dimenticato di aggiornare la funzione lambda corrispondente (ora corretta). La funzione equivalente lavora per Oppure: \a \b a a b. Tuttavia, è più lungo di quello che ho usato in BLC.
Pavel Potoček,

25

Haskell , 50 - 6 = 44 byte

-1 byte grazie a Khuldraeseth na'Barya e -1 byte grazie a Christian Sievers.

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

Provalo online!


2
Nota a margine: è possibile definire Showle istanze per conste const idper stampare direttamente le booleani chiesa. Provalo online! .
nimi,


4
Perché nessuno sta usando f=n t?
Christian Sievers,

3
È possibile salvare un byte utilizzando t=pureinvece di t=const.
Joseph Sible: ripristina Monica il

4
@JosephSible L'ho provato inizialmente. Purtroppo, t=purecauserà un errore quando provo ad applicare a, o, x, o iad essa. Dichiarare il tipo di tcorrezione di questo costa più byte che semplicemente usando t=const.
Nitrodon,

9

Python 2 , (-3?)  101  95 byte

David Beazley ti mangia il cuore!

-6 grazie a Chas Brown (spostato il ripetuto :nel testo di join>. <)

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())

Provalo online!

Penso che potrebbe essere 95 - 3perché non riutilizzare le funzioni A, Xo I, ma io uso un singolo =per l'assegnazione (di fronte lambda). Forse non riesco a rimuovere qualsiasi; forse riesco anche a rimuovere 3.5?


@Ryan Schaefer posso rimuoverne tre o il mio uso di execsignifica che non posso? Vedo andare in entrambi i modi: non riutilizzo A, X o I ma il codice non funzionerà senza di essi. (Forse posso anche rimuovere 3.5 ?!)
Jonathan Allan il


Grazie @Chas! Il colon che è sfuggito alla rete :) Ottimo lavoro sul rimpiazzo per -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)

Provalo online! Il link include casi di test di base. Modifica: salvato 6 9 byte grazie a @tsh.


1
Sembra che non si può pretendere questo come -7 dal t, f, nsono utilizzati.
TSH

1
@tsh Non è così che capisco il sistema di punteggio; esclude esplicitamente il nome nella definizione, sebbene il nome nell'uso abbia un costo di 1 byte.
Neil,

@Neil Non si può pretendere lo sconto di byte per i nomi delle funzioni che sono chiamati dal codice ( t, f, e nnel tuo caso).
asgallant

2
@asgallant no. Non sono byte per il nome e 1 byte quando viene utilizzato in seguito. 'T fnaox i' non sono byte quindi 1 byte se usato in seguito. Volevo migliorare la leggibilità, ma ora mi rendo conto che avrei dovuto lasciarlo completamente golfato ed è troppo tardi per cambiarlo ora
Ryan Schaefer

@RyanSchaefer dov'è quella regola? Non l'ho mai visto così.
asgallant

6

Python 2 , 133 - 6 = 127 94 byte

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:')

Provalo online!

Rubare senza vergogna l'idea subdola dietro la risposta di Jonathan Allan ; nessun byte dedotto però.


Avevo intenzione di pubblicare una risposta alla mia domanda, ma non ero sicuro che ciò fosse consentito e penso che ciò sia contrario allo spirito. Quindi penso che ti guiderò invece lungo. Invece di usare gli elenchi, puoi comunque utilizzare le funzioni che vengono inserite e il modo specifico in cui restituiscono i loro input per abbreviare il codice?
Ryan Schaefer,

Scommetto che, sebbene la risposta sia sì, sarebbe molto più lungo in Python.
Stringa non correlata

Sono corretto
Unrelated String

@ Mr.Xcoder hai ragione, ho avuto il numero errato di byte per la funzione di esempio. Sarebbero autorizzati a rimuovere 6 byte per i nomi delle funzioni.
Ryan Schaefer,

@Sig. Xcoder: modificato secondo le tue osservazioni.
Chas Brown,

4

J , 67 byte - 7 = 60

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

Provalo online!

Vale la pena notare:

Le funzioni di ordine superiore funzionano diversamente in J che in un linguaggio funzionale. Per creare un nuovo verbo da 1 o 2 verbi esistenti, è necessario utilizzare un avverbio (nel caso di 1) o una congiunzione (nel caso di 2).

Sintatticamente, gli avverbi seguono un verbo e le congiunzioni si frappongono tra loro. Quindi "non" un verbo fche fai f n, e "e" verbi fe g, tu f a g.


4

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

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

Provalo online!

senza golf: ispirato a 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]

Abbastanza sicuro che le nuove righe siano necessarie per separare le definizioni delle funzioni. Inoltre fai riferimento a tf e n in altre definizioni di funzioni in modo da non poterle dedurre, quindi 61-4 = 57.
Jonathan Allan il

@JonathanAllan Ho riletto le istruzioni per il punteggio e sono d'accordo che le newline dovrebbero contare, grazie. Non sono d'accordo con la tua seconda parte: quando riutilizzo i nomi, li conto davvero come "1 byte verso il totale dei byte di quel gate", che è implicito qui quando uso i nomi a 1 byte. Mentre la mia lettura delle istruzioni procede, non si fa menzione di contarli ulteriormente come un byte anche per il totale della definizione originale. Quindi vado con N-7 byte. Inoltre, un altro commento dell'OP chiarisce: "Non sono byte per il nome e 1 byte quando viene utilizzato in seguito".
Roman

Ho letto "1 byte dopo" per indicare che l'utilizzo all'interno di un'altra funzione costa un byte. Questo si allinea con il modo in cui anche altri hanno segnato.
Jonathan Allan, il

@JonathanAllan Sono meno interessato all'esegesi e più al golf del codice 😀
Roman

4

Sottocarico , 56 52 byte

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

Provalo online! (include una suite di test e parti identificative testuali del programma)

Questo punteggio sorprendentemente bene per un esolang di livello molto basso. (I numeri della chiesa, i booleani della Chiesa, ecc. Sono molto comunemente usati in Underload per questo motivo; la lingua non ha numeri e booleani incorporati, e questo è uno dei modi più semplici per simularli. Detto questo, è anche comune a codificare i booleani come i numeri della Chiesa 0 e 1.)

Per chiunque sia confuso: Underload ti consente di definire funzioni riutilizzabili, ma non ti consente di nominarle in modo normale, semplicemente galleggiano nello stack di argomenti (quindi se definisci cinque funzioni e vuoi chiamare la prima hai definito, devi scrivere una nuova funzione che accetta cinque argomenti e li chiama il quinto, quindi chiamalo con un numero insufficiente di argomenti in modo che cerchi argomenti di riserva da usare). Chiamarli li distrugge per impostazione predefinita, ma è possibile modificare la chiamata per renderla non distruttiva (in casi semplici, è sufficiente aggiungere due punti alla chiamata, anche se i casi complessi sono più comuni perché è necessario assicurarsi che le copie sullo stack non ti ostacolano), quindi il supporto delle funzioni di Underload ha tutti i requisiti di cui avremmo bisogno dalla domanda.

Spiegazione

vero

(~!)
(  )  Define function:
 ~      Swap arguments
  !     Delete new first argument (original second argument)

Questo è abbastanza semplice; ci liberiamo dell'argomento che non vogliamo e l'argomento che vogliamo rimane lì, fungendo da valore di ritorno.

falso

(!)
( )   Define function:
 !      Delete first argument

Questo è ancora più semplice.

non

((~)~*)
(     )  Define function:
    ~*     Modify first argument by pre-composing it with:
 (~)         Swap arguments

Questo è divertente: not non chiama affatto il suo argomento, usa solo una composizione di funzioni. Questo è un trucco comune in Underload, in cui non si ispeziona affatto i dati, si cambia semplicemente il modo in cui funziona pre e post-composizione delle cose con esso. In questo caso, modifichiamo la funzione per scambiarne gli argomenti prima di eseguire, il che nega chiaramente un numero della Chiesa.

e

:((!)~^)*
 (     )   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 domanda consente di definire le funzioni in termini di altre funzioni. Definiamo "e" in seguito perché più recentemente è stato definito "non", più è facile utilizzarlo. (Questo non sottrae dal nostro punteggio, perché non stiamo affatto nominando "non", ma salva i byte nel scrivere nuovamente la definizione. Questa è l'unica volta in cui una funzione fa riferimento a un'altra, perché si riferisce a qualsiasi funzione ma l'ultimo definito costerebbe troppi byte.)

La definizione qui è and x y = (not x) false y. In altre parole, se not x, allora ritorniamo false; altrimenti, torniamo y.

o

(:^)
(  )  Define function:
 :      Copy the first argument
  ^     Execute the copy, with arguments
          {implicitly, the original first argument}
          {and implicitly, our second argument}

@Nitrodon ha sottolineato nei commenti che or x y = x x yè normalmente più breve di or x y = x true ye che risulta essere corretto anche in Underload. Un'implementazione ingenua di ciò sarebbe (:~^), ma possiamo golfare un byte aggiuntivo notando che non importa se eseguiamo il primo argomento originale o la sua copia, il risultato è lo stesso in entrambi i casi.

Underload in realtà non supporta il curry nel solito senso, ma definizioni come questa lo fanno sembrare così! (Il trucco è che gli argomenti non consumati restano fermi, quindi la funzione chiamata li interpreterà come propri argomenti.)

implica

(~(!)~^(~)~*)
(           )  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 definizione usata qui è implies x y = not (y false x). Se y è vero, questo semplifica not false, ad es true. Se y è falso, questo si semplifica not x, dandoci così la tabella della verità che vogliamo.

In questo caso, stiamo usando di notnuovo, questa volta riscrivendo il suo codice anziché fare riferimento a esso. È solo scritto direttamente come (~)~*senza parentesi, quindi viene chiamato anziché definito.

xor

(()~(~)~^~*)
(          )  Define function:
   ~   ~^       Execute the first argument, with arguments:
    (~)           "swap arguments"
 ()               identity function
         ~*     Precompose the second argument with {the result}

Questa volta, stiamo valutando solo uno dei nostri due argomenti e lo stiamo usando per determinare cosa comporre sul secondo argomento. Underload ti permette di giocare veloce e sciolto con arity, quindi stiamo usando il primo argomento per scegliere tra due funzioni a due argomenti a due ritorni; l'argomento swap che li restituisce entrambi ma nell'ordine opposto e la funzione di identità che li restituisce entrambi nello stesso ordine.

Quando il primo argomento è vero, produciamo quindi una versione modificata del secondo argomento che scambia i suoi argomenti prima dell'esecuzione, ovvero precompone con "argomenti di scambio", vale a dire not. Quindi un vero primo argomento significa che restituiamo notil secondo argomento. D'altra parte, un primo argomento falso significa che componiamo con la funzione identità, cioè non facciamo nulla. Il risultato è un'implementazione di xor.


or x y = x x ysalva alcuni byte or x y = x true y.
Nitrodon,

Sottocarico è spesso controintuitivo quando si tratta di sostituire i valori letterali con variabili riutilizzate, ma in questo caso tale trasformazione si traduce in un risparmio di più byte del previsto, anziché in un minor numero. Grazie per il miglioramento!
ais523,


3

Java 8, punteggio: 360 358 319 271 233 (240-7) byte

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);

Questo è stato più difficile da realizzare di quanto pensassi quando l'ho iniziato .. Soprattutto il implies. Ad ogni modo, funziona .. Probabilmente si può giocare a golf un po 'qua e là. EDIT: Ok, non riutilizzare le funzioni ma duplicare lo stesso approccio è molto più economico in termini di conteggio dei byte per Java .. E ottengo il bonus completo di 7 per non usare nessuna delle funzioni.

Provalo online.

Spiegazione:

// 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 byte

Le interruzioni di riga non sono necessarie (tranne le prime due).

#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_))

Provalo online!

Unit testato con asserzioni come:

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'));

AGGIORNATO: in precedenza avevo avuto

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

ma la risposta di Roman indicava la versione più breve. Si noti che ora not_(std::plus<>)è mal formato, dove precedentemente era equivalente std::plus<>; ma dal momento std::plus<>che "non rappresenta un booleano della Chiesa", penso che entrambi i comportamenti vadano bene secondo le regole.


"Diverso dal primo" non dovrebbe essere aggiornato a "diverso dai primi due"?
LF

@LF: assolutamente corretto. Aggiornato. :)
Quuxplusone il

2

Forth (gforth) , 133 byte - 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 ;

Provalo online!

-4 byte grazie a Quuxplusone

Inizialmente ho riflettuto in modo significativo su questo, considerando cose come macro e letterali, ma poi ho capito che se definissi le cose in termini di vero e falso (come avrei dovuto fare in primo luogo), diventa molto più semplice.

Spiegazione del codice

\ 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
Ripeti la parola lunga executetre volte. Definire la scorciatoia ti : j execute ;farebbe risparmiare 4 byte.
Quuxplusone,

1

SKI-calcolo + C combinatore, 36 byte

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

In realtà non conosco nessun interprete che ti consenta di definire combinatori aggiuntivi in ​​termini di precedenti, quindi ho dovuto testarlo usando http://ski.aditsu.net/ incollando i combinatori desiderati, ad esempio CCKK(SK)pqoutput q, mostrando che Knon implica SK.


1

Julia 1.0 , 36 byte

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

Non so se questo conta, in realtà sto solo sovraccaricando il Booltipo nativo per essere richiamabile, quindi ottengo la maggior parte delle porte logiche gratuitamente. Sfortunatamente, Julia non ha un impliescancello, quindi ho dovuto scrivere la mia funzione.

Provalo online!


Penso che devi ancora includere gli operatori sovraccarichi nella tua presentazione ... ma il punteggio non li conta, dal momento che sono solo nomi? Quindi sarebbero +6 byte dalle newline? Non sono sicuro di come funzioni il punteggio con questa sfida
Jo King,

Non sono sicuro al 100% di come funzioni, ma dover includere un codice che letteralmente non ha nulla per me non ha alcun senso.
user3263164,

Anche se il codice è già stato dichiarato, è necessario includerlo, altrimenti ogni altra lingua di golf sarà zero byte. Non devi assegnarlo a nulla
Jo King il

1

Perl 6 , 120 106 102 101 byte

-1 byte grazie a Jo King

my (\t,\f,&n,&a,&o,&i,&x)={@_[0]},{@_[1]},|<f,t &^v,f t,&^v &^v,t n(&^v),&v>>>.&{"&\{\&^u($_)}".EVAL}

Provalo online!


1

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

Ispirato dal commento-discussione su ciò che conta comunque come una funzione 2-ary, ecco una versione curry della mia precedente soluzione C ++ 17. In realtà è più breve perché possiamo usare la stessa macro per definire not_come definire tutte le altre funzioni!

#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_))

Provalo online!

Questo è testato con affermazioni simili

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

Si noti che or_è definito come efficace

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

Potremmo definire or_più "concisamente" come

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

ma questo ci costerebbe perché non potremmo più usare la Dmacro.


Dato che C ++ fa distinzione tra maiuscole e minuscole, che ne dici di usare Truee Falseinvece di true_e false_? E simile per gli altri operatori. Ciò farà risparmiare 12 byte.
G. Sliepen,

@ G.Sliepen: l'algoritmo di punteggio di OP tiene già conto del fatto che gli identificatori sono effettivamente lunghi un carattere. Citazione: "La lunghezza totale di tutto il codice richiesto per rendere la Chiesa vera e falsa nella tua lingua e il e no o xor e implica porte della Chiesa escluso il nome della funzione. (Ad esempio, false = lambda x, y: y in Python sarebbe 13 byte). Puoi riutilizzare questi nomi in un secondo momento nel tuo codice, contando 1 byte per il totale byte di quel gate. "
Quuxplusone,

Ah, l'ho perso.
G. Sliepen,

0

APL (dzaima / APL) , 47 byte SBCS

Basato sulla soluzione J di Jonah .

truee falsesono funzioni infix, notè un operatore suffix, e il resto sono operatori infix.

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

Come per OP, questo conta tutto da e compreso fino alla fine di ogni linea e conta ogni chiamata una definizione precedente come un singolo byte.

Provalo online!

vero e falso sono le funzioni di identità sinistra e destra.

not scambia semplicemente gli argomenti della sua funzione di operando.

Il resto implementa l'albero decisionale:

andutilizza la funzione per la mano destra per selezionare il risultato della funzione per la mano sinistra se vero, altrimenti il ​​risultato della falsefunzione.

orusa la funzione per la mano sinistra per selezionare trueif se vero, altrimenti il ​​risultato della funzione per la mano destra .

xorusa la funzione destra per selezionare il risultato negato della funzione sinistra ⍶notse vero, altrimenti il ​​risultato della funzione sinistra.

implies utilizza la funzione per mancini per selezionare il risultato della funzione destra se vero, altrimenti il ​​risultato della truefunzione.


0

Stax , 34 byte

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

Eseguilo e esegui il debug su staxlang.xyz!

Spinge un mucchio di blocchi nello stack. Ogni blocco si aspetta il suo ultimo argomento in cima allo stack, seguito in ordine inverso dal resto.

Senza pacchetto (41 byte):

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

Ogni coppia di { }è un blocco. Ho usato i due registri X e Y per trattenerli truee notcosì ho potuto accedervi facilmente in seguito. Sfortunatamente,false non potrebbe essere semplicemente una no-op, in quanto ciò lascerebbe la pila ingombra e rovinerebbe un singolo caso XOR.

Suite di test, commentata

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 byte

Giocando ulteriormente con l'idea di "funzione" in lingue senza funzioni ... ecco una versione Befunge-98 di booleani della Chiesa!

In questo dialetto vincolato di Befunge-98, un programma è costituito da una serie di "linee" o "funzioni", ciascuna delle quali inizia con >un'istruzione (Vai a destra) nella colonna x = 0. Ogni "funzione" può essere identificata con il suo numero di riga (coordinata y). Le funzioni possono ricevere input tramite lo stack di Befunge , come al solito.

La linea 0 è speciale, perché (0,0) è l'IP iniziale. Per creare un programma che esegue la riga L, basta posizionare le istruzioni sulla riga 0 che, una volta eseguito, spostano il puntatore dell'istruzione su (x = L, y = 0).

La magia avviene sulla linea 1. La linea 1, quando eseguita, fa scoppiare un numero Ldalla pila e salta al numero della linea L. (Questa linea era stata in precedenza > >>0{{2u2}2}$-073*-\x, che può "saltare in modo assoluto" a qualsiasi linea; ma ho appena capito che, poiché so che questa linea è collegata alla linea 1, possiamo "saltare in modo relativo" le L-1linee in un diamine di molto meno codice.)

La riga 2 rappresenta Church FALSE. Quando eseguito, estrae due numeri te fdallo stack e quindi vola al numero di riga f.

La riga 3 rappresenta Church TRUE. Quando eseguito, estrae due numeri te fdallo stack e quindi vola al numero di riga t.

La linea 6, che rappresenta Church XOR, è innovativa. Quando eseguito, estrae due numeri ae bdallo stack, quindi vola in linea acon l'input dello stack NOT EXEC b. Quindi sea rappresenta la Chiesa TRUE, il risultato di a NOT EXEC bsarà NOT b; e se arappresenta la Chiesa FALSE, il risultato a NOT EXEC bsarà EXEC b.


Ecco la versione non golfata con imbracatura di prova. Alla riga 0, imposta lo stack con i tuoi input. Ad esempio, 338significa IMPLIES TRUE TRUE. Assicurati che la chiusura xappaia esattamente (x, y) = (0,15) altrimenti non funzionerà nulla! Assicurati anche che la configurazione dello stack inizi con ba, in modo che il programma finisca effettivamente con un po 'di output.

Provalo 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",,,,,@

Ecco la versione di cui ho contato i byte.

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

Si noti che per definire una funzione in questo dialetto non si menziona affatto il suo nome; il suo "nome" è determinato dalla sua posizione di origine. Per chiamare una funzione, devi menzionarne il "nome"; ad esempio, XOR( 6) è definito in termini di NOTe EXEC( 5e 1). Ma tutti i miei "nomi di funzioni" richiedono già solo un byte per rappresentare. Quindi questa soluzione non ottiene regolazioni di punteggio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.