Якщо ви можете перерахувати область функції і порівняти елементи діапазону для рівності, ви можете - досить прямо. Під перерахуванням я маю на увазі наявність усіх доступних елементів. Я буду дотримуватися 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
!
Пакет Control.Monad.Omega може допомогти вам добре переглядати списки кортежів тощо. Я впевнений, що таких пакетів більше, але я їх не знаю.
Звичайно, такий підхід є досить низьким і брутальним, не кажучи вже про некрасивий і неефективний! Тож я закінчу декількома зауваженнями до останньої частини вашого запитання про те, як «писати» бікси. Типова система Haskell не доводить, що функція є біексом - ви дійсно хочете чогось такого, як Agda, - але він готовий вам довіряти.
(Попередження: слід неперевірений код)
Отже, чи можна визначити тип даних Bijection
s між типами 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
константу вручну, може бути досить обмеженою.
Зрештою, якщо ви знаєте, що функція - біекція, ви, сподіваємось, матимете в голові доказ цього факту, який ізоморфізм Кері-Говарда повинен бути здатний перетворити на програму :-)
f x = 1
оберненою величиною 1 є сукупність цілих чисел, а зворотне все інше - порожнє безліч. Незалежно від того, що кажуть деякі відповіді, функція, яка не є бієктивною, не є найбільшою проблемою.