Sottrazione della Chiesa


13

Sottrazione della Chiesa

Il calcolo lambda è sempre stato un mio fascino e i comportamenti emergenti nel passare funzioni l'una nell'altra sono deliziosamente complessi. I numeri di chiesa sono rappresentazioni di numeri naturali derivati ​​dall'applicazione ripetuta di una funzione (normalmente l'aggiunta unaria di una costante). Ad esempio, il numero zero restituisce x e "ignora" la funzione di input, uno è f(x), due è f(f(x))e così via:

ident = lambda x: x
zero = lambda f: ident
succ = lambda n: lambda f: lambda x: f(n(f)(x))
one = succ(zero)
add1 = lambda x: x + 1
to_int = lambda f: f(add1)(0)
print(to_int(one))
>>> 1

Da ciò si può facilmente vedere che l'addizione si ottiene applicando la prima funzione a x quindi applicando la seconda funzione a x:

add = lambda m: lambda n: lambda f: lambda x: n(f)(m(f)(x))
print(to_int(add(one)(two)))
>>> 3

L'aggiunta è relativamente facile da capire. Tuttavia, per un nuovo arrivato potrebbe essere inconcepibile pensare a come appare la sottrazione in un sistema numerico codificato dalla Chiesa. Cosa potrebbe significare eventualmente annullare l'applicazione di una funzione?

Sfida

Implementa la funzione di sottrazione in un sistema numerico codificato dalla Chiesa. Dove la sottrazione esegue l' operazione monus e non applica una funzione nvolte se il risultato sarà maggiore di zero o zero altrimenti. Questo è code-golf, quindi vince il codice più corto.

Ingresso

Due numeri della Chiesa che sono stati codificati nella tua lingua scelta. L'input può essere posizionale o curry. Per provare questi sono numeri veri della Chiesa si devono prendere in qualsiasi funzione e applicarle più volte ( add1è dato negli esempi ma potrebbe essere add25, mult7o qualsiasi altra funzione unario.)

Produzione

Un numero di chiesa. Va notato che se m < nallora m - nè sempre uguale alla funzione identità.

Esempi:

minus(two)(one) = one
minus(one)(two) = zero
...

accettabile anche:

minus(two, one) = one
minus(one, two) = zero

Credito:

Questa idea github per avermi dato un'implementazione in pitone dei numeri della Chiesa.


1
(Il commento nell'essenziale è sbagliato; exp(m, n)calcola m^novviamente.)
Neil,

1
Non sono sicuro di cosa intendi che "l'input può essere posizionale o al curry". È corretto definire la funzione principale come lambda m,n,f:apply f m-n times(o anche lambda m,n,f,x:apply f m-n times to x) anziché lambda m,n:lambda f:...? O questo si applica solo ai due ingressi me n?
xnor

Inoltre, possiamo prendere gli argomenti me nnell'altro ordine? Ciò aiuterebbe con il curry.
xnor

@xnor finché puoi provare che sottrae due numeri di chiesa, puoi prendere gli input come vuoi.
Ryan Schaefer,

Risposte:


9

Haskell , 35 byte

(r%s)f x=s(x:)(iterate f x)!!r(+1)0

Provalo online!

Dillo re ssono le codifiche della chiesa di me n. Vogliamo r%sapplicare i f m-ntempi a un valore iniziale x. Generiamo innanzitutto l'elenco infinito

iterate f x = [x, f x, f (f x), f (f (f x)), ...]

quindi utilizzare s(x:)per anteporre ncopie di x, ovvero spostare ciascun nindice di valore a destra:

s(x:)(iterate f x) = [x, x, x, ...,  x, f x, f (f x), f (f (f x)), ...]

Quindi calcoliamo mdirettamente come r(+1)0e prendiamo l m'elemento di tale elenco come !!r(+1)0. Una soluzione senza indicizzazione potrebbe invece fare head$r tail$..., ovvero eliminare il primo elemento mvolte e quindi prendere il primo elemento, ma la sintassi dell'indicizzazione è molto più breve.

Si noti che la soluzione classica non funziona in Haskell senza estensioni perché la sua tipizzazione forte non può rappresentare l'operazione precedente.


3

Python 2 , 82 80 byte

eval('!u:!v:v(!n:!f:!x:n(!g:!h:h(g(f)))(!u:x)(!u:u))(u)'.replace('!','lambda '))

Provalo online!

2 byte grazie a Nick Kennedy notando una coppia di parentesi non necessaria.

Funzione anonima che implementa meno.

Principalmente si tratta solo di comprimere la definizione trovata nella pagina di Wikipedia; non come ho ancora capito veramente il codice. Ma interessante!


Sulla base dell'essenza citata dall'OP, !u:!v:v(!n:!f:!x:n(!g:!h:h(g(f)))(!y:x)(!x:x))(u)sembra risparmiare 2 byte, ma non capisco davvero il codice!
Nick Kennedy,

@NickKennedy gettingsharper.de/2012/08/30/... se siete interessati
Ryan Schaefer

@Ryan Schaefer: Nice "Trick"!
Chas Brown,

3

Python 2 , 77 byte

lambda r,s:s(lambda r:lambda f:lambda x:r(lambda(_,x):(x,f(x)))((x,x))[0])(r)

Provalo online!

Facciamo un decremento della Chiesa monitorando il valore precedente per ogni iterazione e pubblicandolo alla fine. Il 39% della lunghezza del codice è "lambda"...


simpatico! Stavo aspettando una risposta da golf in pitone che non si limitasse a dare un'occhiata all'implementazione dei contenuti. Hai pensato di usare eval come l'altra risposta per continuare a giocare a golf?
Ryan Schaefer,

@RyanSchaefer Ho controllato cosa valutare / sostituisci quando ho visto l'altra risposta, ma in realtà qui sono 2 byte più lunghi con 5 lambda da sostituire. Python purtroppo è davvero prolisso sia nella definizione delle funzioni che nella manipolazione delle stringhe. E manca un "compose" incorporato, che salverebbe uno strato di lambda.
xnor

2

C ++ (clang) , 112 byte

#define L(x,y)[&](auto x){return y;}
auto m=L(u,L(v,v(L(n,L(f,L(x,n(L(g,L(h,h(g(f)))))(L(u,x))(L(u,u))))))(u)));

Provalo online!

Questo è di gran lunga il codice C ++ più incomprensibile che abbia mai scritto. Detto questo, penso che annullare la registrazione di questo codice non farà che peggiorare le cose.


2

Sottocarico , 37 byte

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

Provalo online!

L'interno (((!())~):*^(~!:(:)~*(*)*)~^^!)è la predfunzione, implementata tramite coppie:

(               ( start pred function )!
  (
    (!())~      ( push zero below argument )!
  ):*^          ( do that twice )!

  (             ( start pair-increasing function )!
    ~!          ( remove second argument)!
    :           ( duplicate first argument )!
    (:)~*(*)*   ( increment first return value )!
  )
  ~^^           ( run pair-increasing function n times )
  !             ( remove first in returned pair )!
)


1

JavaScript (Node.js) , 87 85 81 76 74 byte

f=>g=>h=>x=>f(([x,[g,a]])=>[g(x),a])([x,g(a=>[x=>x,a])(f(a=>[h,a])())])[0]

Provalo online! Non vincerò alcun premio, ma ho pensato di provare un approccio diverso.

a=>[h,a]è una fase che si applica h, mentre a=>[x=>x,a]è una fase che non si applica h. Applichiamo i ftempi della prima funzione e i tempi della seconda funzione g. Quindi applichiamo i ([f,[g,a]])=>[g(x),a] ftempi della funzione inversa . Ciò salta le gseconde fasi ed esegue le f-gprime fasi come desiderato. Resta quindi da estrarre il valore finale.

Le tuple possono ovviamente essere convertite in funzioni lambda che si traducono nella seguente espressione:

f=>g=>h=>x=>f(e=>e(x=>d=>d(g=>a=>e=>e(g(x))(a))))(e=>e(x)(g(a=>e=>e(x=>x)(a))(f(a=>e=>e(h)(a))())))(x=>a=>x)

1

J , 56 byte

c=:3 :0
t=.^:y
5!:1<'t'
)
m=.2 :'c 0>.(>:u 5!:0->:v 5!:0)0'

Provalo online!

Nota: -3 byte fuori dal conteggio TIO perm=.

Le funzioni di ordine superiore in J sono ottenute usando avverbi e congiunzioni. Qui un numero di chiesa è la forma gerundio dell'avverbio formato combinando la congiunzione "potenza di" (che applica ripetutamente un verbo) e un numero intero. Il verbo seguente c(per "creare") usa la Rappresentazione atomica di J per trasformare un intero in un tale gerundio:

c=:3 :0
t=.^:y
5!:1<'t'
)

Il nostro operatore "meno" (che è una congiunzione) sottrae il numero della chiesa gerunda destra da sinistra. Tuttavia, non presuppone alcuna implementazione particolare dei numeri delle chiese, inclusa quella del nostro cverbo. Invece, si basa sulla definizione generale e trasforma ogni chiesa gerund indietro numerale in un avverbio invertendo con 5!:0, e quindi applicando tale avverbio al verbo incremento >:, e applicando poi che a 0.

Quindi sottrae e prende il massimo con 0 e si applica cper ottenere il risultato finale: un nuovo numero di chiesa gerundio.


1

Wolfram Language (Mathematica) , 55 48 47 39 byte (33 caratteri)

#2[(fx#[g#@g@f&][x&][#&])&]@#&

Provalo online!

Il simbolo  è 0xF4A1, uno speciale punto di codice Mathematica che indica una freccia verso destra per \[Function]. Vedi qui per maggiori spiegazioni. Ecco come appare il codice nel front-end di Mathematica:

inserisci qui la descrizione dell'immagine

Possiamo farlo in 40 byte / 32 caratteri , che possono essere più brevi a seconda dello schema di misura:#2[n⟼f⟼x⟼n[g⟼#@g@f&][x&][#&]]@#&

La versione non golfata è una traduzione letterale della definizione classica di pred :

pred = n \[Function] f \[Function] x \[Function] n[g \[Function] h \[Function] h[g[f]]][u \[Function] x][u \[Function] u];
subtract[m_, n_] := n[pred][m]

che assomiglia a questo nel front-end di Mathematica:

inserisci qui la descrizione dell'immagine

Questa funzione di sottrazione funziona con i numeri della Chiesa definiti con

c@0=#& &;c@n_=#@*c[n-1][#]&

(ONU-giocato a golf: c[0] = Identity &; c[n_] = Function[a, a@*c[n-1][a]])

così che abbiamo

Table[c[n][f][x], {n, 0, 6}]
(*    {x, f[x], f[f[x]], f[f[f[x]]], f[f[f[f[x]]]], f[f[f[f[f[x]]]]], f[f[f[f[f[f[x]]]]]]}    *)

e

subtract[c[7],c[5]][f][x]
(*    f[f[x]]    *)
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.