หากคุณสามารถระบุโดเมนของฟังก์ชันและสามารถเปรียบเทียบองค์ประกอบของช่วงเพื่อความเท่าเทียมกันได้คุณสามารถทำได้อย่างตรงไปตรงมา ฉันหมายถึงการมีรายการองค์ประกอบทั้งหมดที่มีอยู่ ฉันจะยึดติดกับ Haskell เนื่องจากฉันไม่รู้จัก Ocaml (หรือแม้กระทั่งวิธีการใช้ประโยชน์อย่างถูกต้อง ;-)
สิ่งที่คุณต้องทำคือเรียกใช้องค์ประกอบของโดเมนและดูว่าพวกมันเท่ากับองค์ประกอบของช่วงที่คุณพยายามจะกลับด้านหรือไม่และเลือกองค์ประกอบแรกที่ได้ผล:
inv :: Eq b => [a] -> (a -> b) -> (b -> a)
inv domain f b = head [ a | a <- domain, f a == b ]
เนื่องจากคุณได้ระบุว่าf
เป็นการคาดคะเนจึงต้องมีองค์ประกอบดังกล่าวเพียงหนึ่งเดียวเท่านั้น เคล็ดลับของหลักสูตรเพื่อให้แน่ใจว่าการแจงนับของคุณของโดเมนจริงถึงองค์ประกอบทั้งหมดในระยะเวลา จำกัด หากคุณกำลังพยายามเปลี่ยนอคติจากInteger
เป็นInteger
ใช้[0,1 ..] ++ [-1,-2 ..]
จะไม่ได้ผลเพราะคุณจะไม่ได้รับค่าลบ รูปธรรมก็inv ([0,1 ..] ++ [-1,-2 ..]) (+1) (-3)
จะไม่ให้ผลคุ้มค่า
แต่จะทำงานในขณะที่วิ่งผ่านทางนี้จำนวนเต็มในลำดับต่อไป0 : concatMap (\x -> [x,-x]) [1..]
[0,1,-1,2,-2,3,-3, and so on]
แน่นอนinv (0 : concatMap (\x -> [x,-x]) [1..]) (+1) (-3)
ทันทีส่งกลับ-4
!
การควบคุมMonad.Omegaแพคเกจสามารถช่วยให้คุณทำงานผ่านรายการของ tuples เป็นต้นในทางที่ดี; ฉันแน่ใจว่ามีแพ็คเกจแบบนั้นมากกว่านี้ - แต่ฉันไม่รู้
แน่นอนว่าแนวทางนี้ค่อนข้างคิ้วต่ำและดุร้ายไม่ต้องพูดถึงน่าเกลียดและไร้ประสิทธิภาพ! ดังนั้นฉันจะปิดท้ายด้วยข้อสังเกตบางส่วนในส่วนสุดท้ายของคำถามของคุณเกี่ยวกับวิธีการ "เขียน" อคติ ระบบประเภทของ Haskell ไม่ได้ขึ้นอยู่กับการพิสูจน์ว่าฟังก์ชั่นเป็น bijection - คุณต้องการบางอย่างเช่น Agda สำหรับสิ่งนั้น - แต่ยินดีที่จะไว้วางใจคุณ
(คำเตือน: โค้ดที่ยังไม่ทดลองติดตาม)
ดังนั้นคุณสามารถกำหนดประเภทข้อมูลBijection
ระหว่างประเภทa
และb
:
data Bi a b = Bi {
apply :: a -> b,
invert :: b -> a
}
พร้อมกับค่าคงที่ให้มากที่สุด (ซึ่งคุณสามารถพูดว่า 'ฉันรู้ว่าพวกมันเป็นอคติ!') ตามที่คุณต้องการเช่น:
notBi :: Bi Bool Bool
notBi = Bi not not
add1Bi :: Bi Integer Integer
add1Bi = Bi (+1) (subtract 1)
และตัวผสมอัจฉริยะสองสามตัวเช่น:
idBi :: Bi a a
idBi = Bi id id
invertBi :: Bi a b -> Bi b a
invertBi (Bi a i) = (Bi i a)
composeBi :: Bi a b -> Bi b c -> Bi a c
composeBi (Bi a1 i1) (Bi a2 i2) = Bi (a2 . a1) (i1 . i2)
mapBi :: Bi a b -> Bi [a] [b]
mapBi (Bi a i) = Bi (map a) (map i)
bruteForceBi :: Eq b => [a] -> (a -> b) -> Bi a b
bruteForceBi domain f = Bi f (inv domain f)
ผมคิดว่าคุณก็จะทำและได้รับinvert (mapBi add1Bi) [1,5,6]
[0,4,5]
หากคุณเลือกตัวรวมของคุณด้วยวิธีที่ชาญฉลาดฉันคิดว่าจำนวนครั้งที่คุณจะต้องเขียนBi
ค่าคงที่ด้วยมืออาจค่อนข้าง จำกัด
ท้ายที่สุดถ้าคุณรู้ว่าฟังก์ชั่นคือการคาดคะเนคุณหวังว่าจะมีภาพร่างพิสูจน์ของความจริงนั้นอยู่ในหัวของคุณซึ่งไอโซมอร์ฟิซึมของ Curry-Howard ควรจะสามารถเปลี่ยนเป็นโปรแกรมได้ :-)
f x = 1
การผกผันของ 1 คือเซตของจำนวนเต็มและสิ่งที่ผกผันของสิ่งอื่นเป็นเซตว่าง ไม่ว่าคำตอบบางคำจะพูดว่าอย่างไรฟังก์ชันที่ไม่เป็นอคติไม่ใช่ปัญหาใหญ่ที่สุด