İşlevin etki alanını numaralandırabilir ve eşitlik aralığının öğelerini karşılaştırabilirseniz, bunu oldukça basit bir şekilde yapabilirsiniz. Numaralandırmakla, mevcut tüm öğelerin bir listesine sahip olmayı kastediyorum. Ocaml'ı bilmediğim için Haskell'e bağlı kalacağım (ya da nasıl büyük harfle yazılacağını bile ;-)
Yapmak istediğiniz şey, etki alanının öğelerini incelemek ve ters çevirmeye çalıştığınız aralığın öğesine eşit olup olmadıklarına bakmak ve işe yarayan ilkini almaktır:
inv :: Eq b => [a] -> (a -> b) -> (b -> a)
inv domain f b = head [ a | a <- domain, f a == b ]
Bunun f
bir bijeksiyon olduğunu belirttiğinize göre , böyle bir unsur olması kaçınılmazdır. İşin püf noktası, elbette, etki alanı numaralandırmanızın aslında tüm öğelere sonlu bir zamanda ulaşmasını sağlamaktır . Eğer bir eşleşme ters çalışıyorsanız Integer
için Integer
kullanırken, [0,1 ..] ++ [-1,-2 ..]
olmaz işi negatif sayılar olsun asla olarak. Somut olarak, inv ([0,1 ..] ++ [-1,-2 ..]) (+1) (-3)
asla bir değer vermeyecektir.
Ancak, 0 : concatMap (\x -> [x,-x]) [1..]
bu tamsayılar aşağıdaki sırayla çalıştığı için çalışacaktır [0,1,-1,2,-2,3,-3, and so on]
. Indeed inv (0 : concatMap (\x -> [x,-x]) [1..]) (+1) (-3)
hemen geri dönüyor -4
!
Control.Monad.Omega paketi iyi bir şekilde küpe vs. listeleri yoluyla yönetmesini sağlayacak; Eminim bunun gibi daha fazla paket vardır - ama onları bilmiyorum.
Tabii ki, bu yaklaşım oldukça alçakgönüllü ve kaba kuvvetlidir, çirkin ve verimsizden bahsetmeye bile gerek yok! Öyleyse, sorunuzun son bölümünde, önyargıları nasıl 'yazacağınıza' dair birkaç yorumla bitireceğim. Haskell'in tip sistemi, bir fonksiyonun bir bijeksiyon olduğunu kanıtlamakla kalmaz - bunun için gerçekten Agda gibi bir şey istersiniz - ama size güvenmeye isteklidir.
(Uyarı: test edilmemiş kod izler)
Yani, Bijection
türler arasında bir veri türü tanımlayabilir a
ve b
:
data Bi a b = Bi {
apply :: a -> b,
invert :: b -> a
}
İstediğiniz kadar sabitle birlikte (burada ' Önyükleme olduklarını biliyorum !' diyebilirsiniz !), örneğin:
notBi :: Bi Bool Bool
notBi = Bi not not
add1Bi :: Bi Integer Integer
add1Bi = Bi (+1) (subtract 1)
ve birkaç akıllı birleştirici, örneğin:
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)
Bence o zaman yapabilir invert (mapBi add1Bi) [1,5,6]
ve alabilirsin [0,4,5]
. Kombinatörlerinizi akıllıca seçerseniz Bi
, elle sabit yazmak zorunda kalacağınız zamanın sayısı oldukça sınırlı olabilir.
Sonuçta, eğer bir fonksiyonun bijeksiyon olduğunu biliyorsanız, umarım bu gerçeğin kafanızda Curry-Howard izomorfizminin bir programa dönüştürebilmesi gereken bir kanıt taslağı olur :-)
f x = 1
1'in tersinin bir tamsayılar kümesi olduğunu ve başka herhangi bir şeyin tersinin boş bir küme olduğunu söylemek yanlış değildir . Bazı yanıtların ne dediğine bakılmaksızın, işlevin önyargılı olmaması en büyük sorun değildir.