En lenguajes funcionales puros como Haskell, ¿existe un algoritmo para obtener la inversa de una función, (editar) cuando es biyectiva? ¿Y hay una forma específica de programar su función para que sea así?
haskell
clojure
functional-programming
ocaml
MaiaVictor
fuente
fuente
f x = 1
, el inverso de 1 es un conjunto de números enteros y el inverso de cualquier otra cosa es un conjunto vacío. Independientemente de lo que digan algunas respuestas, la función no ser biyectiva no es el mayor problema.f
es una funcióng
tal quef . g = id
yg . f = id
. En ese caso, su candidato ni siquiera realiza la verificación a máquina.f x = 1
no tiene inversa adoptan un enfoque muy estrecho e ignoran toda la complejidad del problema.Respuestas:
En algunos casos, ¡sí! ¡Hay un hermoso artículo llamado Bidireccionalización gratis! que analiza algunos casos, cuando su función es suficientemente polimórfica, donde es posible, de forma completamente automática, derivar una función inversa. (También analiza qué dificulta el problema cuando las funciones no son polimórficas).
Lo que se obtiene en el caso de que su función sea invertible es la inversa (con una entrada falsa); en otros casos, obtiene una función que intenta "fusionar" un valor de entrada antiguo y un valor de salida nuevo.
fuente
put
funciones en cualquier estructura de registro que deriveData
: haskell.org/pipermail/haskell-cafe/2008-April/042193.html usando un enfoque similar a que luego presentó (más rigurosamente, más en general, más principios, etc.) en "gratis".No, no es posible en general.
Prueba: considere funciones biyectivas de tipo
con
Supongamos que tenemos un inversor
inv :: F -> F
tal queinv f . f ≡ id
. Digamos que lo hemos probado para la funciónf = id
, confirmando queDado que este primero
B0
en la salida debe haber llegado después de un tiempo finito, tenemos un límite superiorn
tanto en la profundidad a la queinv
realmente se evaluó nuestra entrada de prueba para obtener este resultado, como en el número de veces que puede haber llamadof
. Defina ahora una familia de funcionesClaramente, para todos
0<j≤n
,g j
es una biyección, de hecho, autoinversa. Entonces deberíamos poder confirmarpero para cumplir con esto,
inv (g j)
habría necesitadog j (B1 : repeat B0)
a una profundidad den+j > n
head $ g j l
al menosn
diferentes listas que coincidanreplicate (n+j) B0 ++ B1 : ls
Hasta ese momento, al menos uno de los
g j
es indistinguible def
, y dado queinv f
no había realizado ninguna de estas evaluaciones,inv
no podría haberlo diferenciado, salvo realizar algunas mediciones en tiempo de ejecución por sí solo, lo que solo es posible en elIO Monad
.⬜
fuente
Puede buscarlo en wikipedia, se llama Computación reversible .
Sin embargo, en general no puede hacerlo y ninguno de los lenguajes funcionales tiene esa opción. Por ejemplo:
Esta función no tiene inversa.
fuente
f
tiene una inversa, es solo que la inversa es una función no determinista?g :: Int -> a
que sea la inversa def
, incluso si puede describir la inversa def
matemáticamente.f x = 2 * x
serf' x = [x / 2]
, y luego el inverso def _ = 1
esf' 1 = [minBound ..]; f' _ = []
. Es decir, hay muchas inversas para 1 y ninguna para cualquier otro valor.No en la mayoría de los lenguajes funcionales, pero en la programación lógica o la programación relacional, la mayoría de las funciones que define no son funciones, sino "relaciones", y se pueden utilizar en ambas direcciones. Consulte, por ejemplo, prolog o kanren.
fuente
Tareas como esta casi siempre son indecidibles. Puede tener una solución para algunas funciones específicas, pero no en general.
Aquí, ni siquiera puede reconocer qué funciones tienen una inversa. Citando a Barendregt, HP El cálculo Lambda: su sintaxis y semántica. Holanda Septentrional, Amsterdam (1984) :
Tomemos A como el conjunto de términos lambda que representan funciones invertibles y B el resto. Ambos no están vacíos y cerrados bajo igualdad beta. Por tanto, no es posible decidir si una función es invertible o no.
(Esto se aplica al cálculo lambda sin tipo. TBH no sé si el argumento se puede adaptar directamente a un cálculo lambda con tipo cuando conocemos el tipo de función que queremos invertir. Pero estoy bastante seguro de que será similar.)
fuente
Si puede enumerar el dominio de la función y comparar elementos del rango para determinar la igualdad, puede hacerlo de una manera bastante sencilla. Por enumerar me refiero a tener una lista de todos los elementos disponibles. Me quedaré con Haskell, ya que no sé Ocaml (ni siquiera cómo capitalizarlo correctamente ;-)
Lo que desea hacer es ejecutar los elementos del dominio y ver si son iguales al elemento del rango que está tratando de invertir, y tomar el primero que funcione:
Como ha dicho que
f
es una biyección, es probable que haya uno y solo uno de esos elementos. El truco, por supuesto, es asegurarse de que su enumeración del dominio alcance realmente todos los elementos en un tiempo finito . Si está tratando de invertir una biyección deInteger
aInteger
, el uso[0,1 ..] ++ [-1,-2 ..]
no funcionará ya que nunca obtendrá los números negativos. Concretamente,inv ([0,1 ..] ++ [-1,-2 ..]) (+1) (-3)
nunca rendirá un valor.Sin embargo,
0 : concatMap (\x -> [x,-x]) [1..]
funcionará, ya que se ejecuta a través de los números enteros en el siguiente orden[0,1,-1,2,-2,3,-3, and so on]
. De hechoinv (0 : concatMap (\x -> [x,-x]) [1..]) (+1) (-3)
regresa rápidamente-4
!El paquete Control.Monad.Omega puede ayudarlo a ejecutar listas de tuplas, etcétera, de una buena manera; Estoy seguro de que hay más paquetes como ese, pero no los conozco.
Por supuesto, este enfoque es bastante sencillo y de fuerza bruta, ¡sin mencionar que es feo e ineficiente! Así que terminaré con algunos comentarios sobre la última parte de su pregunta, sobre cómo 'escribir' bijecciones. El sistema de tipos de Haskell no está preparado para demostrar que una función es una biyección (realmente quieres algo como Agda para eso) pero está dispuesto a confiar en ti.
(Advertencia: sigue un código no probado)
Entonces, ¿puede definir un tipo de datos de
Bijection
s entre tiposa
yb
:junto con tantas constantes (donde puede decir '¡ Sé que son biyecciones!') como desee, como:
y un par de combinadores inteligentes, como:
Creo que entonces podrías hacer
invert (mapBi add1Bi) [1,5,6]
y conseguir[0,4,5]
. Si elige sus combinadores de una manera inteligente, creo que la cantidad de veces que tendrá que escribir unBi
constante a mano podría ser bastante limitada.Después de todo, si sabe que una función es una biyección, es de esperar que tenga un bosquejo de prueba de ese hecho en su cabeza, que el isomorfismo de Curry-Howard debería poder convertir en un programa :-)
fuente
Recientemente he estado lidiando con problemas como este, y no, diría que (a) no es difícil en muchos casos, pero (b) no es eficiente en absoluto.
Básicamente, suponga que lo ha hecho
f :: a -> b
, y esof
es de hecho un error. Puedes calcular la inversaf' :: b -> a
de una manera realmente tonta:Si
f
es una biyección yenumerate
realmente produce todos los valores dea
, eventualmente llegará aa
tal quef a == b
.Los tipos que tienen una instancia
Bounded
y una seEnum
pueden hacer trivialmenteRecursivelyEnumerable
.Enumerable
También se pueden hacer pares de tiposEnumerable
:Lo mismo ocurre con las disyunciones de
Enumerable
tipos:El hecho de que podamos hacer esto para
(,)
yEither
probablemente significa que podemos hacerlo para cualquier tipo de datos algebraicos.fuente
No todas las funciones tienen una inversa. Si limita la discusión a funciones uno a uno, la capacidad de invertir una función arbitraria otorga la capacidad de descifrar cualquier criptosistema. Tenemos que esperar que esto no sea factible, ¡incluso en teoría!
fuente
String encrypt(String key, String text)
sin la clave, todavía no podrá hacer nada. EDITAR: Además de lo que dijo delnan.En algunos casos, es posible encontrar la inversa de una función biyectiva convirtiéndola en una representación simbólica. Basado en este ejemplo , escribí este programa de Haskell para encontrar inversas de algunas funciones polinomiales simples:
Este ejemplo solo funciona con expresiones aritméticas, pero probablemente podría generalizarse para trabajar también con listas.
fuente
No, ni siquiera todas las funciones tienen inversas. Por ejemplo, ¿cuál sería la inversa de esta función?
fuente