มีวิธีที่สะดวกในการใช้รูปแบบเป็นฟังก์ชันเพรดิเคตหรือไม่


10

เมื่อเร็ว ๆ นี้ฉันได้พบกับสถานการณ์ที่ฉันต้องการส่งผ่านฟังก์ชันเพรดิเคตไปยังฟังก์ชั่นอื่นและบ่อยครั้งที่ตรรกะที่ฉันกำลังค้นหาคือ "ค่านี้ตรงกับรูปแบบนี้หรือไม่"

การจับคู่รูปแบบดูเหมือนจะเป็นที่ต้องการในการประกาศdoบล็อกและรายการความเข้าใจ แต่มีฟังก์ชันจำนวนมากที่ใช้คำกริยาa -> Boolซึ่งเป็นประโยชน์อย่างมากหากผ่านไปในรูปแบบ ตัวอย่างเช่นtakeWhile, until, find, spanฯลฯ

จนถึงขณะนี้ฉันได้ทำ\a -> case a of MyCons _ -> True; otherwise -> Falseหรือเขียนฟังก์ชั่นที่มีชื่อ la let myPred (MyCons _) = True; myPred _ = False inแต่พวกเขาทั้งสองดูเหมือนน่าเกลียดชะมัดและไม่สำนวนมาก วิธี "ชัดเจน" (และผิด) จะเป็นสิ่งที่ชอบ\(MyCons _) -> Trueแต่นั่นทำให้เกิดข้อผิดพลาดในการเป็นบางส่วนโดยธรรมชาติและถึงแม้จะรู้สึกว่าต้องมีวิธีที่สะอาดกว่า

มีวิธีรวบรัด / สะอาดกว่านี้ในการทำสิ่งนี้หรือไม่? หรือฉันจะทำสิ่งต่าง ๆ โดยสิ้นเชิงผิด?


1
บางทีนี่อาจเป็น "รสนิยมส่วนตัว" แต่ถ้าคุณต้องการเพรดิเคตนี้ในที่เดียวฉันมีความสุขมากกับletประโยคที่คุณไม่ชอบ - แม้ว่าฉันจะชอบwhereประโยคที่เทียบเท่ากัน แน่นอนว่าถ้าคุณต้องการยูทิลิตี้นี้มากกว่าหนึ่งครั้งคุณจะต้องกำหนดให้เป็นฟังก์ชันระดับบนสุด
Robin Zigmond

มันใช้งานได้ดีอย่างแน่นอน คำถามของฉันค่อนข้างมีแรงจูงใจจากความย่อของ Haskell มันมักจะรู้สึกเหมือนสำนวน Haskell มีการทำซ้ำความคิดน้อยมากและทำให้ปุยน้อยที่สุด ดังนั้นไม่จำเป็นว่าฉันจะคิดว่าlet myPred...สไตล์ไม่ดีแต่มันให้ความรู้สึกละเอียดมากกว่าที่ฉันคาดไว้สำหรับความคิดที่ง่ายมากซึ่งทำให้ฉันสงสัยว่าฉันเห่าต้นไม้ผิดไปหรือเปล่า
David Sampson

2
คุณอาจดูปริซึม (จากเลนส์) พวกเขาเป็นเหมือนรูปแบบการ
แต่งเพลง

1
ฉันคิดว่าเราต้องเห็นตัวอย่างว่าคุณใช้ฟังก์ชันลำดับที่สูงกว่าประเภทนี้อย่างไร ส่วนหนึ่งของฉันอยากจะบอกว่าปัญหาอยู่ที่การออกแบบที่ต้องใช้คำกริยาในตอนแรก
chepner

วิธี Haskell98 สำหรับสิ่งนี้คือการกำหนดฟังก์ชั่นการจับคู่ case (deconstructing) สำหรับชนิดข้อมูลของคุณเช่นmaybe :: b -> (a -> b) -> Maybe a -> bและbool :: a -> a -> Bool -> aจากนั้นใช้กับฟังก์ชันบูลีนที่สร้างเป็นอาร์กิวเมนต์ เช่นนั้นเรียกmyCons z f (MyCons x) = f x ; myCons z f _ = z myCons False (const True) aMyConsValueนี่คือสิ่งที่คุณเขียนเกือบจะมีเพียง "ระดับทางอ้อม" / "นามธรรม" อีกระดับหนึ่งผ่านการโต้แย้งเชิงฟังก์ชันอบเข้ามา
Will Ness

คำตอบ:


7

คุณสามารถใช้ Language Extension LambdaCase เพื่อใช้งาน\case MyCons _ -> True; _ -> Falseได้แม้ว่าจะไม่ได้บันทึกอักขระจำนวนมาก

ผมเชื่อว่าคุณสามารถเขียนชุดของฟังก์ชั่นconstructedWith :: (Generic a) => (b -> a) -> a -> Bool, constructedWith2 :: (Generic a) => (b -> c -> a) -> a -> Boolแต่ฉันไม่ได้มีอำนาจมากพอกับยาสามัญที่จะดำเนินการได้โดยไม่ต้องไม่กี่ชั่วโมงการทดสอบสิ่งที่ออก ฉันจะลองทำสิ่งนี้และแก้ไขคำตอบของฉันหากฉันสามารถหาคำตอบได้หรือถ้ามันเป็นจุดจบ

แก้ไข: ใช่คุณสามารถทำได้! นี่คือลิงค์ไปยังรหัสของฉันซึ่งใช้ทั้งหมดตั้งแต่ต้น:

https://repl.it/@lalaithion/ConstructedWith

อย่างไรก็ตามการใช้งานบางอย่างเช่นhttp://hackage.haskell.org/package/generic-deriving-1.13.1/docs/Generics-Deriving-ConNames.htmlสำหรับระบบประปารหัสทั่วไปทั้งหมดอาจจะดีกว่า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.