교회 빼기


13

교회 빼기

람다 미적분학은 항상 내 마음에 매료되어 왔으며 함수를 서로에게 전달하는 출현 행동은 유쾌하게 복잡합니다. 교회 숫자 는 함수의 반복적 인 적용 (일반적으로 상수의 단항 추가)으로 구성된 자연수의 표현입니다. 예를 들어, 숫자 0은 x를 반환하고 입력 함수는 "무시"합니다. 하나는 f(x), 2는 f(f(x))등입니다.

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

이것으로부터 우리는 x에 첫 번째 함수를 적용한 다음 x에 두 번째 함수를 적용하여 추가가 달성되었음을 쉽게 알 수 있습니다.

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

덧셈은 비교적 이해하기 쉽다. 그러나 새로 온 사람에게는 교회에서 인코딩 된 숫자 시스템에서 빼기가 어떻게 보이는지 생각할 수 없습니다. 함수를 적용 취소한다는 것은 무엇을 의미 할 수 있습니까?

도전

교회 인코딩 숫자 시스템에서 빼기 기능을 구현하십시오. 빼기가 monus 연산을 수행하고 n결과가 0보다 크면 함수 시간을 적용 하지 않으면 그렇지 않습니다. 이것은 코드 골프이므로 가장 짧은 코드가 승리합니다.

입력

선택한 언어로 인코딩 된 두 교회 숫자. 입력은 위치 또는 커리가 될 수 있습니다. 이들은 참된 교회의 숫자를 증명하기 위해 그들은 어떤 기능에 걸릴 반복적으로 적용해야합니다 ( add1예제에 나와 있지만, 수 add25, mult7또는 다른 단항 기능.)

산출

교회 숫자. m < n그렇다면 m - n항상 항등 함수와 동일 하다는 점에 유의해야합니다 .

예 :

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

또한 허용 :

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

신용:

github 는 Church Numerals의 파이썬 구현을 제공합니다.


1
(요점의 의견이 잘못되었습니다. 물론 exp(m, n)계산 m^n합니다.)
Neil

1
"입력이 위치 또는 카레 일 수 있습니다"라는 것이 무슨 의미인지 잘 모르겠습니다. 주 함수를 대신 lambda m,n,f:apply f m-n times(또는 심지어 lambda m,n,f,x:apply f m-n times to x) 정의 해도 lambda m,n:lambda f:...됩니까? 또는 이것은 단지 두 개의 입력에 적용 되는가 mn?
xnor

또한 우리는 논쟁 mn다른 순서로 취할 수 있습니까? 이것은 카레에 도움이 될 것입니다.
xnor

@xnor는 두 개의 교회 숫자를 뺀다는 것을 증명할 수 있다면 원하는대로 입력 할 수 있습니다.
라이언 쉐퍼

답변:


9

하스켈 , 35 바이트

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

온라인으로 사용해보십시오!

그 말을 r하고 s교회 인코딩은 mn. 초기 값에 시간 r%s을 적용 하고 싶습니다 . 먼저 무한리스트를 생성합니다f m-nx

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

그런 s(x:)다음를 사용 하여의 n사본 을 앞에 붙여서 x즉, 각 값 n인덱스를 오른쪽으로 이동하십시오.

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

그런 다음로 m직접 계산 r(+1)0하고 m해당 목록 의 '번째 요소를로 사용 !!r(+1)0합니다. 인덱싱이없는 솔루션은 대신 head$r tail$...첫 번째 요소 m시간을 삭제 한 다음 첫 번째 요소를 사용하지만 인덱싱 구문은 훨씬 짧습니다.

있습니다 고전 솔루션은 강력한 타이핑이 이전 작업을 나타낼 수 없기 때문에 확장하지 않고 하스켈에서 작동하지 않습니다.


3

파이썬 2 , 82 80 바이트

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

온라인으로 사용해보십시오!

2 바이트는 Nick Kennedy 에게 불필요한 쌍의 페어를 표시합니다.

빼기를 구현하는 익명 함수.

대부분 위키피디아 페이지에있는 정의를 압축하고 있습니다. 코드를 아직 이해하고 있지는 않습니다. 그러나 재미있는!


OP가 언급 한 요지에 따라 !u:!v:v(!n:!f:!x:n(!g:!h:h(g(f)))(!y:x)(!x:x))(u)2 바이트를 절약하는 것처럼 보이지만 실제로 코드를 이해하지 못합니다!
Nick Kennedy

@NickKennedy gettingsharper.de/2012/08/30/… 관심이 있으시 다면
Ryan Schaefer

@Ryan Schaefer : 멋진 "트릭"!
Chas Brown

3

파이썬 2 , 77 바이트

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

온라인으로 사용해보십시오!

각 반복에 대한 이전 값을 추적하고 마지막에 출력하여 교회 감소를 수행합니다. 코드 길이의 39 %는 "lambda"의 ...


좋은! 요점 구현을 보지 않은 골프 파이썬 답변을 기다리고있었습니다. 골프를 더하기 위해 다른 대답과 같이 eval을 사용하는 것에 대해 생각해 보셨습니까?
Ryan Schaefer

@RyanSchaefer 나는 다른 대답을 볼 때 eval / replace 일을 확인했지만 실제로는 5 람다로 2 바이트 더 깁니다. 불행히도 파이썬은 함수를 정의하고 문자열을 조작하는 데있어서 정말 장황합니다. 그리고 내장 된 "구성"이 없어서 람다 층을 절약 할 수 있습니다.
xnor

2

C ++ (clang) , 112 바이트

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

온라인으로 사용해보십시오!

이것은 내가 작성한 것 중 가장 이해하기 어려운 C ++ 코드입니다. 즉,이 코드를 풀면 코드가 더 나빠질 것이라고 생각합니다.


2

언더로드 , 37 바이트

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

온라인으로 사용해보십시오!

내부 (((!())~):*^(~!:(:)~*(*)*)~^^!)pred쌍을 통해 구현 되는 함수입니다.

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

자바 스크립트 (Node.js) , 87 85 81 76 74 bytes

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

온라인으로 사용해보십시오! 수상을하지는 않지만 다른 접근법을 시도 할 것이라고 생각했습니다.

a=>[h,a]적용되는 단계 h이고, a=>[x=>x,a]적용되지 않는 단계입니다 h. 첫 번째 기능 f시간과 두 번째 기능 시간을 적용합니다 g. 그런 다음 역함수 ([f,[g,a]])=>[g(x),a] f시간 을 적용합니다 . 이는 g두 번째 단계를 건너 뛰고 f-g원하는대로 첫 번째 단계를 수행 합니다. 그런 다음 최종 값을 추출합니다.

튜플은 물론 람다 함수로 변환되어 다음과 같은 표현이 가능합니다.

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 바이트

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

온라인으로 사용해보십시오!

참고 : TIO 카운트에서 -3 바이트m=.

J의 고차 함수는 부사와 연결을 사용하여 달성됩니다. 여기서 교회 숫자는 "동력의 힘"(동사를 반복적으로 적용 함)과 정수를 결합하여 형성되는 부사의 거론 형태입니다. 다음 동사 c( "create"용)는 J의 Atomic Representation 을 사용 하여 정수를 그런 제럴드로 변환합니다.

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

우리의 "빼기"연산자 (연합)는 왼쪽에서 오른쪽 gerund 교회 숫자를 뺍니다. 그러나 c동사 의 동사를 포함하여 교회 숫자의 특정 구현을 가정하지는 않습니다 . 대신, 일반적인 정의에 의존하고 그것을 반전 부사로 각 동명사 교회 부호 등을 전환 5!:0하고 증가 동사에 그 부사를 적용 >:하고 적용 0.

그런 다음 0을 빼고 최대 값을 취하여 c최종 결과를 얻는 데 적용 합니다. 새로운 gerund 교회 숫자.


1

Wolfram Language (Mathematica) , 55 48 47 39 바이트 (33 자)

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

온라인으로 사용해보십시오!

 기호는 0xF4A1이며, 오른쪽 화살표를 나타내는 특수 Mathematica 코드 포인트입니다 \[Function]. 자세한 설명 은 여기참조하십시오 . Mathematica 프론트 엔드에서 코드는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

우리는 40 바이트 / 32 문자 로 할 수 있으며 측정 체계에 따라 더 짧을 수 있습니다.#2[n⟼f⟼x⟼n[g⟼#@g@f&][x&][#&]]@#&

ungolfed 버전은 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]

Mathematica 프론트 엔드에서 다음과 같이 보입니다.

여기에 이미지 설명을 입력하십시오

이 빼기 기능은 다음과 같이 정의 된 교회 숫자와 함께 작동합니다

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

(골프 제외 c[0] = Identity &; c[n_] = Function[a, a@*c[n-1][a]])

그래서 우리는

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]]]]]]}    *)

subtract[c[7],c[5]][f][x]
(*    f[f[x]]    *)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.