การลบคริสตจักร


13

การลบคริสตจักร

แลมบ์ดาแคลคูลัสเป็นที่สนใจของฉันมาโดยตลอดและพฤติกรรมฉุกเฉินของการส่งผ่านหน้าที่ต่าง ๆ เข้ามามีความซับซ้อนอย่างน่ายินดี เลขคริสตจักรเป็นตัวแทนของตัวเลขธรรมชาติที่สร้างขึ้นจากการใช้ฟังก์ชั่นซ้ำ ๆ (โดยปกติจะเป็นการเพิ่มค่าคงที่แบบเอกภาพ) ตัวอย่างเช่นจำนวนศูนย์ส่งคืน x และ "ละเว้น" ฟังก์ชันอินพุตหนึ่งคือf(x)สองคือ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ถ้าผลลัพธ์จะมากกว่าศูนย์หรือศูนย์ นี่คือรหัส - กอล์ฟเพื่อให้ได้รหัสที่สั้นที่สุด

อินพุต

ตัวเลขสองคริสตจักรที่ได้รับการเข้ารหัสในภาษาที่คุณเลือก อินพุตสามารถเป็นตำแหน่งหรือ curried เพื่อพิสูจน์ว่าตัวเลขคริสตจักรเหล่านี้เป็นจริงพวกเขาจะต้องใช้เวลาในการทำงานใด ๆ และนำไปใช้ซ้ำ ๆ ( add1จะได้รับในตัวอย่าง แต่มันอาจจะเป็นadd25, mult7หรือฟังก์ชั่นเอกอื่น ๆ .)

เอาท์พุต

เลขคริสตจักร ควรสังเกตว่าถ้าเป็นเช่นm < nนั้นm - nเสมอกับฟังก์ชั่นตัวตน

ตัวอย่าง:

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

ยังเป็นที่ยอมรับ:

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

เครดิต:

สรุปสาระสำคัญนี้เพื่อให้ฉันการดำเนินการหลามของเลขคริสตจักร


1
(ความคิดเห็นในส่วนสำคัญไม่ถูกต้องexp(m, n)คำนวณm^nแน่นอน)
นีล

1
ฉันไม่แน่ใจว่าสิ่งที่คุณหมายถึงว่า "การป้อนข้อมูลสามารถเป็นตำแหน่งหรือ curried" มันตกลงเพื่อกำหนดฟังก์ชั่นหลักเป็น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:...? หรือนี่ใช้กับอินพุตทั้งสองmและn?
xnor

นอกจากนี้เราอาจจะโต้แย้งmและnในลำดับอื่น ๆ ได้ไหม? สิ่งนี้จะช่วยในการแกง
xnor

@ xnor ตราบใดที่คุณสามารถพิสูจน์ได้ว่ามันลบเลขสองตัวของคริสตจักรแล้วคุณสามารถรับอินพุตต่อไปได้ตามที่คุณต้องการ
Ryan Schaefer

คำตอบ:


9

Haskell , 35 ไบต์

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

ลองออนไลน์!

บอกได้เลยว่าrและsมีการเข้ารหัสของคริสตจักรและm nเราต้องการr%sที่จะใช้เวลาบางส่วนค่าเริ่มต้นf m-n xเราสร้างรายการที่ไม่มีที่สิ้นสุดก่อน

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จากนั้นใช้องค์ประกอบแรก แต่ไวยากรณ์การทำดัชนีนั้นสั้นกว่ามาก

โปรดทราบว่าโซลูชันแบบคลาสสิกใช้งานไม่ได้ใน Haskell หากไม่มีส่วนขยายเนื่องจากการพิมพ์ที่รัดกุมไม่สามารถแสดงถึงการทำงานของรุ่นก่อนได้


3

Python 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สังเกตว่าไม่จำเป็นคู่ parens

ฟังก์ชั่นไม่ระบุชื่อที่ใช้ลบ

ส่วนใหญ่เป็นเพียงการบีบอัดคำจำกัดความที่พบในหน้า Wikipedia ไม่เหมือนฉันเข้าใจรหัสอย่างแท้จริง แต่น่าสนใจ!


ตามส่วนที่กล่าวถึง 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: Nice "Trick"!
Chas Brown

3

Python 2 , 77 ไบต์

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

ลองออนไลน์!

เราจะลดค่าคริสตจักรโดยการติดตามค่าก่อนหน้าสำหรับการทำซ้ำแต่ละครั้งและส่งออกในตอนท้าย 39% ของความยาวรหัสคือ"lambda"...


ดี! ฉันกำลังรอคำตอบหลาม golfed ที่ไม่เพียงแค่ดูการดำเนินการส่วนสำคัญ คุณเคยคิดที่จะใช้ eval เหมือนคำตอบอื่นในการเล่นกอล์ฟต่อไปหรือไม่?
Ryan Schaefer

@ RyanSchaefer ฉันตรวจสอบ eval / replace สิ่งเมื่อฉันเห็นคำตอบอื่น ๆ แต่จริงๆแล้วมันมีความยาว 2 ไบต์ที่นี่พร้อมกับ 5 lambdas เพื่อแทนที่ Python เป็นคำที่น่าเสียดายจริงๆทั้งในการกำหนดฟังก์ชั่นและการจัดการสตริง และมันก็ไม่มี "การเขียน" ที่ติดตั้งในตัวซึ่งจะช่วยปกป้องชั้นแกะ
xnor

2

C ++ (เสียงดังกราว) , 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

JavaScript (Node.js) , 87 85 81 76 74 ไบต์

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แรกตามที่ต้องการ จากนั้นจะยังคงแยกค่าสุดท้าย

แน่นอน tuples สามารถถูกแปลงเป็นฟังก์ชันแลมบ์ดาซึ่งส่งผลให้เกิดนิพจน์ต่อไปนี้:

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'

ลองออนไลน์!

หมายเหตุ: -3 ไบต์ปิดนับ TIO สำหรับm=.

ฟังก์ชันลำดับที่สูงขึ้นใน J สามารถทำได้โดยใช้คำวิเศษณ์และคำสันธาน นี่คือตัวเลขของคริสตจักรคือรูปแบบ gerund ของคำวิเศษณ์ที่เกิดขึ้นจากการรวม "พลังของ" การรวมกัน (ซึ่งใช้กริยาซ้ำ ๆ ) และจำนวนเต็ม คำกริยาต่อไปนี้c(สำหรับ "สร้าง") ใช้การแทนปรมาณูของ J เพื่อแปลงจำนวนเต็มให้เป็นคำกริยา:

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

โอเปอเรเตอร์ "ลบ" ของเรา (ซึ่งเป็นการรวมกัน) จะลบตัวเลข gerund โบสถ์ขวาจากด้านซ้าย อย่างไรก็ตามมันไม่ถือว่ามีการใช้ตัวเลขคริสตจักรโดยเฉพาะรวมถึงสิ่งที่มาจากcกริยาของเรา แต่มันต้องอาศัยความหมายทั่วไปและเปลี่ยนแต่ละอาการนามคริสตจักรเลขกลับเข้ามาในคำวิเศษณ์โดย inverting มันด้วย5!:0และจากนั้นใช้คำวิเศษณ์ที่คำกริยาที่เพิ่มขึ้น>:และจากนั้นใช้ที่ 0

จากนั้นจะลบและใช้เวลาสูงสุดด้วย 0 และนำcไปใช้เพื่อให้ได้ผลลัพธ์สุดท้าย: ตัวเลข gerund โบสถ์ใหม่


1

ภาษา Wolfram (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&][#&]]@#&

รุ่นที่ไม่ตีกอล์ฟคือการแปลความหมายดั้งเดิมของคำจำกัดความดั้งเดิมของ 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.