Jika Anda dapat menghitung domain fungsi dan dapat membandingkan elemen rentang untuk persamaan, Anda dapat - dengan cara yang cukup mudah. Dengan menyebutkan maksud saya memiliki daftar semua elemen yang tersedia. Saya akan tetap menggunakan Haskell, karena saya tidak tahu Ocaml (atau bahkan cara memanfaatkannya dengan benar ;-)
Apa yang ingin Anda lakukan adalah menjalankan melalui elemen domain dan melihat apakah mereka sama dengan elemen rentang yang Anda coba balikkan, dan ambil yang pertama yang berfungsi:
inv :: Eq b => [a] -> (a -> b) -> (b -> a)
inv domain f b = head [ a | a <- domain, f a == b ]
Karena Anda telah menyatakan itu f
sebuah perhiasan, pasti ada satu dan hanya satu elemen semacam itu. Triknya, tentu saja, adalah memastikan bahwa penghitungan domain Anda benar-benar mencapai semua elemen dalam waktu yang terbatas . Jika Anda mencoba membalikkan bijeksi dari Integer
menjadi Integer
, penggunaan [0,1 ..] ++ [-1,-2 ..]
tidak akan berhasil karena Anda tidak akan pernah mendapatkan angka negatif. Secara konkret,inv ([0,1 ..] ++ [-1,-2 ..]) (+1) (-3)
tidak akan pernah menghasilkan nilai.
Namun, 0 : concatMap (\x -> [x,-x]) [1..]
akan berfungsi, karena ini berjalan melalui bilangan bulat dalam urutan berikut [0,1,-1,2,-2,3,-3, and so on]
. Memang inv (0 : concatMap (\x -> [x,-x]) [1..]) (+1) (-3)
segera kembali-4
!
The Control.Monad.Omega paket dapat membantu Anda menjalankan melalui daftar tupel sebagainya dengan cara yang baik; Saya yakin ada lebih banyak paket seperti itu - tetapi saya tidak mengetahuinya.
Tentu saja, pendekatan ini agak kasar dan kasar, belum lagi jelek dan tidak efisien! Jadi saya akan mengakhiri dengan beberapa komentar di bagian terakhir pertanyaan Anda, tentang bagaimana 'menulis' bijections. Sistem tipe Haskell tidak cukup untuk membuktikan bahwa suatu fungsi adalah sesuatu yang bijak - Anda benar-benar menginginkan sesuatu seperti Agda untuk itu - tetapi ia bersedia mempercayai Anda.
(Peringatan: mengikuti kode yang belum diuji)
Jadi, dapatkah Anda menentukan tipe data Bijection
antara tipe a
dan b
:
data Bi a b = Bi {
apply :: a -> b,
invert :: b -> a
}
bersama dengan banyak konstanta (di mana Anda dapat mengatakan 'Saya tahu itu bijections!') sesuka Anda, seperti:
notBi :: Bi Bool Bool
notBi = Bi not not
add1Bi :: Bi Integer Integer
add1Bi = Bi (+1) (subtract 1)
dan beberapa kombinator cerdas, seperti:
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)
Saya pikir Anda kemudian bisa melakukan invert (mapBi add1Bi) [1,5,6]
dan mendapatkan [0,4,5]
. Jika Anda memilih kombinator dengan cara yang cerdas, saya rasa berapa kali Anda harus menulis fileBi
konstanta dengan tangan bisa sangat terbatas.
Lagi pula, jika Anda tahu suatu fungsi adalah bijeksi, semoga Anda memiliki sketsa bukti fakta itu di kepala Anda, yang seharusnya dapat diubah oleh isomorfisme Curry-Howard menjadi sebuah program :-)
f x = 1
, invers dari 1 adalah himpunan bilangan bulat dan invers dari yang lainnya adalah himpunan kosong. Terlepas dari apa yang dikatakan beberapa jawaban, fungsi bukan bijective bukanlah masalah terbesar.