อ่าน 5 นาที
เคอร์รี่ (ภาษาโปรแกรม)
Curryเป็น ภาษา การเขียนโปรแกรมเชิงประกาศซึ่งเป็นการนำแนวคิดการเขียนโปรแกรมเชิงตรรกะเชิงฟังก์ชัน มาใช้ และอิงตาม ภาษา...
เคอร์รี่ (ภาษาโปรแกรม)
| แกง | |
|---|---|
| กระบวนทัศน์ | ฟังก์ชันนัล ตรรกะไม่เข้มงวด โมดูลาร์ |
| ออกแบบโดย | ไมเคิล ฮานุส, เซอร์จิโอ อันตอย และคณะ |
| นักพัฒนา | มหาวิทยาลัยคีล มหาวิทยาลัยแอลเอ็มยูมิวนิกมหาวิทยาลัยมุนสเตอร์มหาวิทยาลัยพอร์ตแลนด์สเตท มหาวิทยาลัยคอมพลูเตนเซแห่งมาดริดมหาวิทยาลัยเทคนิคแห่งมาดริด |
| ปรากฏครั้งแรก | พ.ศ. 2538 |
| เวอร์ชันเสถียร | 3.8.0 [ 1 ] |
| วินัยในการพิมพ์ | คงที่แข็งแกร่งอนุมานได้ |
| แพลตฟอร์ม | x86-64 |
| โอเอส | ใช้งานได้กับหลายแพลตฟอร์ม : ลินุกซ์ |
| ใบอนุญาต | เงื่อนไข BSD 3 ข้อ |
| เว็บไซต์ | www.curry-lang.org |
| การนำไปใช้งานหลักๆ | |
| PAKCS ( เป้าหมาย Prolog ), mcc ( เป้าหมายC ), KiCS2 ( เป้าหมาย Haskell ) | |
| ได้รับอิทธิพลจาก | |
| ฮัสเคลล์ , โพรล็อก | |
Curryเป็น ภาษา การเขียนโปรแกรมเชิงประกาศซึ่งเป็นการนำแนวคิดการเขียนโปรแกรมเชิงตรรกะเชิงฟังก์ชัน มาใช้ [ 2 ] [ 3 ] [ 4 ]และอิงตาม ภาษา Haskellโดยผสานรวมองค์ประกอบของการเขียนโปรแกรมเชิงฟังก์ชันและเชิงตรรกะ[ 5 ]รวมถึงการบูรณา การการเขียนโปรแกรมแบบมีข้อจำกัด
ภาษา Curry เกือบจะเป็นซูเปอร์เซตของ Haskell แต่ไม่รองรับส่วนขยายภาษาทั้งหมดของ Haskell แตกต่างจาก Haskell ตรงที่ Curry มีการสนับสนุนในตัวสำหรับการคำนวณแบบไม่แน่นอนที่เกี่ยวข้องกับการค้นหา
พื้นฐานของการเขียนโปรแกรมเชิงตรรกะแบบฟังก์ชัน
แนวคิดพื้นฐาน
โปรแกรมเชิงฟังก์ชันคือชุดของฟังก์ชันที่กำหนดโดยสมการหรือกฎ การคำนวณเชิงฟังก์ชันประกอบด้วยการแทนที่นิพจน์ย่อยด้วยนิพจน์ย่อยที่เท่ากัน (โดยคำนึงถึงนิยามของฟังก์ชัน) จนกว่าจะไม่สามารถแทนที่ (หรือลดรูป) ได้อีกต่อไป และได้ค่าหรือรูปแบบปกติ ตัวอย่างเช่น พิจารณาฟังก์ชัน double ที่กำหนดโดย
x สองเท่า = x+x
นิพจน์ “ 1 สองเท่า ” จะถูกแทนที่ด้วย1+1ซึ่งสามารถแทนที่ด้วย2 ได้ หากเราตีความตัวดำเนินการ “ + ” ว่าถูกกำหนดโดยชุดสมการอนันต์ เช่น1+1 = 2 , 1+2 = 3เป็นต้น ในทำนองเดียวกัน เราสามารถประเมินนิพจน์ที่ซ้อนกันได้ (โดยที่นิพจน์ย่อยที่จะถูกแทนที่นั้นอยู่ในเครื่องหมายคำพูด):
'double (1+2)' → '(1+2)'+(1+2) → 3+'(1+2)' → '3+3' → 6
นอกจากนี้ ยังมีลำดับการประเมินอีกแบบหนึ่ง หากเราสลับอาร์กิวเมนต์ของตัวดำเนินการจากขวาไปซ้าย:
'double (1+2)' → (1+2)+'(1+2)' → '(1+2)'+3 → '3+3' → 6
ในกรณีนี้ การคำนวณทั้งสองวิธีให้ผลลัพธ์เดียวกัน ซึ่งเป็นคุณสมบัติที่เรียกว่าการบรรจบกัน (confluence ) สิ่งนี้เป็นผลมาจากคุณสมบัติพื้นฐานของภาษาโปรแกรมเชิงฟังก์ชันบริสุทธิ์ที่เรียกว่าความโปร่งใสเชิงอ้างอิง (referential transparency ) กล่าวคือ ค่าของผลลัพธ์ที่คำนวณได้ไม่ขึ้นอยู่กับลำดับหรือเวลาของการประเมิน เนื่องจากไม่มีผลข้างเคียง (side effects ) สิ่งนี้ช่วยให้การทำความเข้าใจและการบำรุงรักษาโปรแกรมเชิงฟังก์ชันบริสุทธิ์ง่ายขึ้น
เช่นเดียวกับภาษาโปรแกรมเชิงฟังก์ชันหลายภาษาอย่างHaskellภาษา Curry รองรับการกำหนดชนิดข้อมูลเชิงพีชคณิตโดยการแจงนับตัวสร้างของชนิดข้อมูลเหล่านั้น ตัวอย่างเช่น ชนิดข้อมูลของค่าบูลีนประกอบด้วยตัวสร้างTrueและFalseซึ่งประกาศไว้ดังนี้:
ข้อมูลบูลีน= จริง| เท็จฟังก์ชันบนค่าบูลีนสามารถกำหนดได้โดยการจับคู่รูปแบบ กล่าวคือ โดยการระบุสมการหลายสมการสำหรับค่าอาร์กิวเมนต์ที่แตกต่างกัน:
ไม่จริง= เท็จไม่เท็จ= จริงหลักการแทนที่สิ่งที่เท่ากันด้วยสิ่งที่เท่ากันยังคงใช้ได้ตราบใดที่อาร์กิวเมนต์จริงมีรูปแบบที่ต้องการ เช่น:
ไม่ใช่ '(ไม่ใช่เท็จ)' → 'ไม่ใช่จริง' → เท็จ
โครงสร้างข้อมูลที่ซับซ้อนยิ่งขึ้นสามารถสร้างขึ้นได้โดยใช้ชนิดข้อมูลแบบเรียกซ้ำตัวอย่างเช่น รายการขององค์ประกอบ โดยที่ชนิดขององค์ประกอบเป็นแบบใดก็ได้ (ระบุโดยตัวแปรชนิดa ) อาจเป็นรายการว่าง “ [] ” หรือรายการที่ไม่ว่าง “ x:xs ” ซึ่งประกอบด้วยองค์ประกอบแรกxและรายการxs :
รายการข้อมูลa = [] | a : รายการaโดยทั่วไปแล้ว ประเภท “ List a ” จะเขียนเป็น[a]และลิสต์จำกัดx 1 : x 2 : … : x n :[]จะเขียนเป็น[ x 1 , x 2 , … , x n ]เราสามารถกำหนดการดำเนินการบนประเภทแบบเรียกซ้ำได้โดยใช้คำจำกัดความแบบอุปนัย ซึ่งการจับคู่รูปแบบช่วยให้สามารถแยกกรณีต่างๆ ได้อย่างสะดวก ตัวอย่างเช่น การดำเนินการต่อเชื่อม “ ++ ” บนลิสต์แบบโพลีมอร์ฟิกสามารถกำหนดได้ดังนี้ (การประกาศประเภทที่เป็นตัวเลือกในบรรทัดแรกระบุว่า “ ++ ” รับลิสต์สองรายการเป็นอินพุตและสร้างลิสต์เอาต์พุต โดยที่องค์ประกอบทั้งหมดในลิสต์มีประเภทเดียวกันที่ไม่ระบุ):
( ++ ) :: [ a ] -> [ a ] -> [ a ] [] ++ ys = ys ( x : xs ) ++ ys = x : xs ++ ysนอกเหนือจากการนำไปใช้ในงานเขียนโปรแกรมต่างๆ แล้ว ตัวดำเนินการ “ ++ ” ยังมีประโยชน์ในการกำหนดพฤติกรรมของฟังก์ชันอื่นๆ บนลิสต์อีกด้วย ตัวอย่างเช่น พฤติกรรมของฟังก์ชัน last ที่ส่งคืนองค์ประกอบสุดท้ายของลิสต์ สามารถกำหนดได้ดังนี้: for all lists xs and elements e, last xs = e if ∃ ys : ys ++[ e ] = xs.
จากข้อกำหนดนี้ เราสามารถกำหนดฟังก์ชันที่ตรงตามข้อกำหนดนี้ได้โดยใช้คุณสมบัติของการเขียนโปรแกรมเชิงตรรกะ เช่นเดียวกับภาษาตรรกะ ภาษาตรรกะเชิงฟังก์ชันช่วยให้สามารถค้นหาคำตอบสำหรับตัวแปรที่มีปริมาณแบบมีอยู่จริงได้ ในทางตรงกันข้ามกับภาษาตรรกะบริสุทธิ์ ภาษาตรรกะเชิงฟังก์ชันรองรับการแก้สมการเหนือการแสดงออกเชิงฟังก์ชันที่ซ้อนกัน ดังนั้นสมการเช่นys ++[ e ] = [1,2,3]จึงสามารถแก้ไขได้โดยการกำหนดค่า ys ให้กับลิสต์[1,2]และeให้กับค่า3ในภาษา Curry เราสามารถกำหนดการดำเนินการ last ได้ดังนี้:
สุดท้ายxs | ys ++ [ e ] =:= xs = e โดยที่ys , e เป็นอิสระในที่นี้ สัญลักษณ์ “ =:= ” ใช้สำหรับข้อจำกัดเชิงสมการ เพื่อให้เกิดความแตกต่างทางไวยากรณ์จากสมการนิยาม ในทำนองเดียวกัน ตัวแปรเพิ่มเติม (เช่น ตัวแปรที่ไม่ได้ปรากฏในด้านซ้ายของสมการนิยาม) จะถูกประกาศอย่างชัดเจนโดย “ where … free ” เพื่อให้มีโอกาสตรวจจับข้อผิดพลาดที่เกิดจากการพิมพ์ผิด สมการเงื่อนไขในรูปแบบL | C = Rสามารถนำไปใช้ในการลดรูปได้ หากเงื่อนไขCได้รับการแก้ไขแล้ว ในทางตรงกันข้ามกับภาษาฟังก์ชันบริสุทธิ์ที่เงื่อนไขจะถูกประเมินเป็นค่าบูลีนเท่านั้น ภาษาตรรกะเชิงฟังก์ชันสนับสนุนการแก้เงื่อนไขโดยการเดาค่าสำหรับตัวแปรที่ไม่ทราบค่าในเงื่อนไข การจำกัดขอบเขตดังที่กล่าวไว้ในส่วนถัดไปจะถูกนำมาใช้เพื่อแก้เงื่อนไขประเภทนี้
การแคบลง
การจำกัดขอบเขต (Narrowing) เป็นกลไกที่กำหนดค่าให้กับตัวแปรหนึ่งๆ โดยเลือกค่าจากตัวเลือกต่างๆ ที่กำหนดโดยข้อจำกัด แต่ละค่าที่เป็นไปได้จะถูกลองใช้ตามลำดับ และส่วนที่เหลือของโปรแกรมจะถูกเรียกใช้ในแต่ละกรณีเพื่อตรวจสอบความถูกต้องของการกำหนดค่า การจำกัดขอบเขตเป็นการต่อยอดจากการเขียนโปรแกรมเชิงตรรกะ (Logic Programming) ตรงที่มันทำการค้นหาในลักษณะเดียวกัน แต่สามารถสร้างค่าต่างๆ ขึ้นมาได้ในระหว่างการค้นหา แทนที่จะจำกัดอยู่แค่การทดสอบค่าเหล่านั้นเท่านั้น
การจำกัดขอบเขตมีประโยชน์เพราะช่วยให้สามารถมองฟังก์ชันเป็นความสัมพันธ์ได้ กล่าวคือ สามารถคำนวณค่าของฟังก์ชันได้ "ทั้งสองทิศทาง" ตัวอย่างของ Curry ในหัวข้อก่อนหน้านี้แสดงให้เห็นถึงเรื่องนี้
ดังที่กล่าวไว้ในส่วนก่อนหน้า การจำกัดขอบเขตสามารถคิดได้ว่าเป็นการลดกราฟเทอมของโปรแกรม และมักจะมีหลายวิธี ( กลยุทธ์ ) ที่แตกต่างกันในการลดกราฟเทอมที่กำหนด Antoy et al. [ 6 ]พิสูจน์ในช่วงทศวรรษ 1990 ว่ากลยุทธ์การจำกัดขอบเขตเฉพาะอย่างหนึ่ง คือ การจำกัดขอบเขตที่จำเป็น นั้น เหมาะสมที่สุดในแง่ของการดำเนินการลดจำนวนหนึ่งเพื่อให้ได้ "รูปแบบปกติ" ที่สอดคล้องกับวิธีแก้ปัญหาที่น้อยที่สุดในบรรดากลยุทธ์ที่ถูกต้องและสมบูรณ์ การจำกัดขอบเขตที่จำเป็น นั้น สอดคล้องกับกลยุทธ์แบบขี้เกียจ ตรงกันข้ามกับ กลยุทธ์ การแก้ปัญหา SLDของProlog
รูปแบบการทำงาน
กฎที่กำหนดสุดท้ายที่แสดงไว้ข้างต้นแสดงให้เห็นว่าอาร์กิวเมนต์จริงต้องตรงกับผลลัพธ์ของการจำกัดนิพจน์ys++[e] Curry สามารถแสดงคุณสมบัตินี้ได้ในรูปแบบที่กระชับกว่าดังต่อไปนี้:
สุดท้าย( ys ++ [ e ]) = eHaskell ไม่อนุญาตให้ประกาศแบบนั้น เนื่องจากรูปแบบทางด้านซ้ายมือมีฟังก์ชันที่กำหนดไว้ ( ++ ) รูปแบบดังกล่าวเรียกว่า รูป แบบฟังก์ชัน[ 7 ]รูปแบบฟังก์ชันเกิดขึ้นจากการรวมคุณสมบัติเชิงฟังก์ชันและตรรกะของ Curry และสนับสนุนคำจำกัดความที่กระชับของงานที่ต้องการการจับคู่รูปแบบเชิงลึกในโครงสร้างข้อมูลแบบลำดับชั้น
ความไม่แน่นอน
เนื่องจาก Curry สามารถแก้สมการที่มีการเรียกใช้ฟังก์ชันด้วยค่าที่ไม่ทราบค่าได้ กลไกการทำงานของมันจึงอาศัยการคำนวณแบบไม่แน่นอน คล้ายกับการเขียนโปรแกรมเชิงตรรกะ กลไกนี้ยังรองรับการกำหนดการดำเนินการแบบไม่แน่นอนกล่าวคือ การดำเนินการที่ให้ผลลัพธ์มากกว่าหนึ่งอย่างสำหรับอินพุตที่กำหนด ต้นแบบของการดำเนินการแบบไม่แน่นอนคือการดำเนินการแบบอินฟิกซ์ที่กำหนดไว้ล่วงหน้า?ซึ่งเรียกว่า ตัวดำเนินการ เลือกที่ส่งคืนอาร์กิวเมนต์ตัวใดตัวหนึ่ง ตัวดำเนินการนี้ถูกกำหนดโดยกฎต่อไปนี้:
x ? y = x x ? y = y
ดังนั้น การประเมินนิพจน์0 ? 1จึงให้ผลลัพธ์เป็น0และ1การคำนวณด้วยการดำเนินการที่ไม่แน่นอนและการคำนวณด้วยตัวแปรอิสระโดยการจำกัดขอบเขตมีพลังการแสดงออกที่เท่ากัน[ 8 ]
กฎที่กำหนด?แสดงให้เห็นถึงคุณลักษณะสำคัญของ Curry: กฎทั้งหมดจะถูกทดลองใช้เพื่อประเมินการดำเนินการบางอย่าง ดังนั้นจึงสามารถกำหนดได้โดย
แทรกx ys = x : ys แทรกx ( y : ys ) = y : แทรกx ysการดำเนินการเพื่อแทรกองค์ประกอบลงในรายการ ณ ตำแหน่งที่ไม่แน่นอน เพื่อให้การดำเนินการนั้นเป็นไปตามที่กำหนดไว้
perm [] = [] perm ( x : xs ) = insert x ( perm xs )ส่งคืนลำดับการเรียงสับเปลี่ยนใดๆ ของรายการอินพุตที่กำหนด
กลยุทธ์
เนื่องจากไม่มีผลข้างเคียง โปรแกรมตรรกะเชิงฟังก์ชันจึงสามารถทำงานได้ด้วยกลยุทธ์ที่แตกต่างกัน ในการประเมินนิพจน์ Curry ใช้ กลยุทธ์การ จำกัดขอบเขตที่จำเป็น แบบหนึ่ง ซึ่งผสมผสานการประเมินแบบขี้เกียจเข้ากับกลยุทธ์การค้นหาแบบไม่กำหนด ในทางตรงกันข้ามกับ Prolog ซึ่งใช้การย้อนกลับเพื่อค้นหาคำตอบ Curry ไม่ได้กำหนดกลยุทธ์การค้นหาเฉพาะเจาะจง ดังนั้นจึงมีการใช้งาน Curry ในรูปแบบต่างๆ เช่นKiCS2ซึ่งผู้ใช้สามารถเลือกกลยุทธ์การค้นหาได้อย่างง่ายดาย เช่นการค้นหาเชิงลึก (การย้อนกลับ) การ ค้นหาเชิงกว้าง การค้นหาเชิงลึกแบบวนซ้ำ หรือการค้นหาแบบขนาน
การนำไปใช้และเครื่องมือการเขียนโปรแกรม
มีการใช้งาน Curry หลายรูปแบบ ตัวอย่างที่โดดเด่นที่สุด ได้แก่ Portland Aachen Kiel Curry System (PAKCS)ซึ่งคอมไพล์โปรแกรม Curry เป็นProlog , Kiel Curry System (KiCS2)ซึ่งคอมไพล์โปรแกรม Curry เป็นHaskell , Münster Curry Compiler (MCC)และCurry2Goซึ่งคอมไพล์โปรแกรม Curry เป็น โปรแกรม Goและรองรับการค้นหาแบบขนานที่เป็นธรรมโดยการแมปการประเมินที่ไม่แน่นอนไปยังกระบวนการขนาดเล็ก (goroutines)
เพื่อสนับสนุนการเขียนโปรแกรมด้วยภาษา Curry นั้น มีชุดซอฟต์แวร์ Curry , เครื่องมือค้นหา API ของ Curry , เซิร์ฟเวอร์ภาษา Curryที่ให้ การสนับสนุน IDEเช่น ในVisual Studio Codeรวมถึงเครื่องมือจัดทำเอกสารและวิเคราะห์โปรแกรมต่างๆ
การอภิปรายและการอ่านเพิ่มเติม
John Alan Robinsonได้กล่าวถึงการบูรณาการการเขียนโปรแกรมเชิงฟังก์ชันกับการเขียนโปรแกรมเชิงตรรกะในบทความ CL2000 ที่ได้รับเชิญ[ 9 ]โดยเขาเขียนว่า: "เป็นเรื่องที่อธิบายไม่ได้ว่าทำไมสำนวนทั้งสองจึงถูกแยกออกจากกันเป็นเวลานานภายในคลังตรรกะการคำนวณ เราต้องการภาษาการเขียนโปรแกรมเดียวที่การเขียนโปรแกรมทั้งสองประเภทเป็นไปได้และสามารถใช้ร่วมกันได้" เขาได้สำรวจความพยายามต่างๆ และสรุปว่า Curry เป็น "ตัวเลือกที่น่าสนใจที่สุด"
ตำราเรียน[ 10 ]เกี่ยวกับหลักการและการปฏิบัติของภาษาการเขียนโปรแกรมมีบทหนึ่งเกี่ยวกับการเขียนโปรแกรมในภาษาเคอร์รี
ลิงก์ภายนอก
- เว็บไซต์อย่างเป็นทางการ
- Smap - สภาพแวดล้อมการประมวลผลบนเว็บสำหรับภาษา Curry และ Haskell พร้อมโปรแกรมตัวอย่างมากมาย
- แพ็กเกจ Curry - ชุดซอฟต์แวร์สำหรับโปรแกรม Curry
- MCC - โปรแกรมคอมไพเลอร์แกงกะหรี่เมืองมุนสเตอร์ มุ่งเป้าไปที่ภาษาC
- PAKCSคือการนำ Curry มาใช้ในวงกว้าง โดยมุ่งเป้าไปที่Prolog
- KiCS2คือการใช้งาน Curry โดยมุ่งเป้าไปที่ภาษา Haskell
- Curry2Goคือการใช้งาน Curry สำหรับภาษาGoและรองรับการค้นหาแบบขนานที่เป็นธรรม
- คลังเก็บข้อมูล GitHubที่มีการใช้งานและเครื่องมือ Curry
- รายชื่อผู้รับจดหมายของ Curry
- โฮมเพจของไมเคิล ฮานัส
- การเขียนโปรแกรมเชิงฟังก์ชันแบบขี้เกียจที่ไม่แน่นอน (Fischer, Kiselyov, Shan, 2009) และการแปลงโปรแกรมตรรกะเชิงฟังก์ชันเป็นโปรแกรมเชิงฟังก์ชันแบบเอกภาค (Braßel, Fischer, Hanus, Reck, 2010) เป็นเรื่องเกี่ยวกับการสร้างแบบจำลองการเขียนโปรแกรมเชิงตรรกะแบบขี้เกียจที่ไม่แน่นอน (เช่นในภาษา Curry) ในภาษาเชิงฟังก์ชันล้วนๆ ( Haskell ) แนวทางดังกล่าวอาจทำให้นักเขียนโปรแกรมมีความยืดหยุ่นมากขึ้นในการควบคุมกลยุทธ์ต่างๆ ซึ่งในกรณีของ Curry นั้นเป็นกลยุทธ์ที่ถูกกำหนดไว้แล้ว
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ เคอร์รี่ (ภาษาโปรแกรม)
Curryเป็น ภาษา การเขียนโปรแกรมเชิงประกาศซึ่งเป็นการนำแนวคิดการเขียนโปรแกรมเชิงตรรกะเชิงฟังก์ชัน มาใช้ และอิงตาม ภาษา...
แนวคิดพื้นฐาน
โปรแกรมเชิงฟังก์ชันคือชุดของฟังก์ชันที่กำหนดโดยสมการหรือกฎ การคำนวณเชิงฟังก์ชันประกอบด้วยการแทนที่นิพจน์ย่อยด้วยนิพจน์ย่อยที่เท่ากัน (โดยคำนึงถึงนิยามของฟังก์ชัน) จนกว่าจะไม่สามารถแทนที่ (หรือลดรูป) ได้อีกต่อไป และได้ค่าหรือรูปแบบปกติ ตัวอย่างเช่น...
การแคบลง
การจำกัดขอบเขต (Narrowing) เป็นกลไกที่ กำหนด ค่าให้กับตัวแปรหนึ่งๆ โดยเลือกค่าจากตัวเลือกต่างๆ ที่กำหนดโดยข้อจำกัด แต่ละค่าที่เป็นไปได้จะถูกลองใช้ตามลำดับ และส่วนที่เหลือของโปรแกรมจะถูกเรียกใช้ในแต่ละกรณีเพื่อตรวจสอบความถูกต้องของการกำหนดค่า...
รูปแบบการทำงาน
กฎที่กำหนด สุดท้าย ที่แสดงไว้ข้างต้นแสดงให้เห็นว่าอาร์กิวเมนต์จริงต้องตรงกับผลลัพธ์ของการจำกัดนิพจน์ ys++[e] Curry สามารถแสดงคุณสมบัตินี้ได้ในรูปแบบที่กระชับกว่าดังต่อไปนี้: