คำตอบนี้เป็นส่วนหนึ่งของการทำงานร่วมกันระหว่างฉันกับ 0 ' เราทั้งคู่ทำสิ่งนี้ด้วยกันเหตุผลเดียวที่ฉันโพสต์คือเพราะฉันได้รับรางวัลร็อคกระดาษกรรไกร
\Q-->{Q=1};"(",\N,")",\B,{findnsols(N,I,(between(2,inf,I),\+ (between(3,I,U),0=:=I mod(U-1))),L)->append(_,[Y],L),Q is Y*B}.
ลองออนไลน์!
คำอธิบาย
คำตอบนี้เป็นแบบอย่างที่สมบูรณ์แบบของสิ่งที่ทำให้การเล่นกอล์ฟเป็นไปอย่างสนุกสนาน
คำตอบนี้ใช้ระบบที่มีประสิทธิภาพ Prologs สำหรับไวยากรณ์ประโยคที่ชัดเจน นี่คือหลักไวยากรณ์ของเรา
head(1)-->[].
head(Q)-->"(",head(N),")",head(B),{prime(N,Y),Q is Y*B}.
isprime(I):- \+ (between(3,I,U),0 =:= I mod(U-1)).
prime(N,Y):-
findnsols(N,I,(
between(2,inf,I),
isprime(I)
),L),
append(_,[Y],L),!.
กฎการก่อสร้างแรกคือ:
head(1)-->[].
สิ่งนี้จะบอก Prolog ว่าสตริงว่างสอดคล้องกับ 1
กฎการก่อสร้างข้อที่สองของเราซับซ้อนกว่าเล็กน้อย
head(Q)-->"(",head(N),")",head(B),{prime(N,Y),Q is Y*B}.
สิ่งนี้บอกเราว่าสตริงที่ไม่ว่างใด ๆ มีวงเล็บอยู่รอบ clause ด้วยกฎเดียวกันนี้ทางด้านขวาของ clause ที่มีกฎเดียวกันเหล่านี้
นอกจากนี้ยังบอกเราว่ามูลค่าของข้อนี้ ( Q) เป็นไปตามกฎ:
{prime(N,Y),Q is Y*B}
หมดสภาพนี้Qเป็นผลิตภัณฑ์ของ 2 ตัวเลขและ Y เป็นเพียงค่าของส่วนคำสั่งทางด้านซ้ายและเป็นส่วนที่สำคัญที่เป็นค่าของส่วนคำสั่งในวงเล็บBBYNN
กฎนี้ครอบคลุมทั้งกฎการก่อตัวของทรีแฟคเตอร์
- การต่อข้อมูลแบบทวีคูณ
- สิ่งที่แนบมาใช้เวลาที่สำคัญที่
ตอนนี้สำหรับคำจำกัดความของคำกริยา ในเวอร์ชั่นที่ไม่ดีมีสองภาคที่เล่น (ในรหัสจริงของฉันฉันไปข้างหน้าล่ามโซ่ภาคไป) เพรดิเคตที่เกี่ยวข้องทั้งสองที่นี่คือisprime/1ซึ่งตรงกับจำนวนเฉพาะและprime/2ที่กำหนดNและYตรงกับ iff YคือNth ไพรม์ ก่อนอื่นเรามี
isprime(I):- \+ (between(3,I,U),0 =:= I mod(U-1)).
ผลงานของคำนิยามมาตรฐานสวยของ primality นี้เรายืนยันว่ามีจำนวนระหว่าง 2 และไม่Iรวมถึง 2 แต่ไม่ว่าแบ่งII
ภาคต่อไปนี้ก็ค่อนข้างง่าย
prime(N,Y):-
findnsols(N,I,(
between(2,inf,I),
isprime(I)
),L),
append(_,[Y],L),!.
เราใช้findnsolsเพื่อหาNตัวเลขแรกที่เป็นจำนวนเฉพาะเราจะคืนค่าตัวเลขสุดท้าย เคล็ดลับที่นี่คือในขณะที่findnsolsไม่รับประกันว่าจะหาช่วงเวลาที่น้อยที่สุด Nเพราะวิธีการที่ SWI จัดการbetweenนั้นจะพบช่วงเวลาที่เล็กกว่าในไม่ช้า อย่างไรก็ตามนี่หมายความว่าเราต้องตัดเพื่อป้องกันไม่ให้หาช่วงเวลาที่มากขึ้น
นักกอล์ฟ
เราสามารถส่งต่อเหตุผลในรหัสของเราสองครั้ง ตั้งแต่ใช้เพียงครั้งเดียวหมายของมันสามารถเคลื่อนย้ายภายในของisprime primeสิ่งต่อไปคือการย้ายprimeโดยตรงภายใน DCG อย่างไรก็ตามเนื่องจากเราใช้การตัดprimeเพื่อป้องกันfindnsolsการผลิตช่วงเวลาที่มากเกินไปเราจึงมีปัญหาเล็กน้อย การตัดเป็นการลด DCG ทั้งหมดแทนที่จะเป็นบิตที่เราต้องการ หลังจากการขุดเอกสารเล็กน้อยเราพบว่าonce/1สามารถใช้ตัดส่วนนี้ได้ แต่ไม่ใช่ DCG ทั้งหมด อย่างไรก็ตามการขุดเอกสารเพิ่มเติมพบว่า->ผู้ปฏิบัติงานสามารถใช้เพื่อทำงานที่คล้ายกันได้ ->ผู้ประกอบการคือประมาณเทียบเท่ากับ,!,เพื่อให้เราย้ายไปตัดของเราไปยังด้านอื่น ๆ ของและแทนที่ด้วยappend/3->
ใน SWI-Prolog predicates (และกฎ) สามารถให้โอเปอเรเตอร์เป็นชื่อซึ่งช่วยให้เราสามารถวางวงเล็บที่จำเป็นตามปกติ ดังนั้นเราสามารถบันทึก 6 \ไบต์โดยการเรียกกฎ