Em linguagens puramente funcionais como Haskell, existe um algoritmo para obter o inverso de uma função, (editar) quando ela é bijetiva? E existe uma maneira específica de programar sua função assim?
haskell
clojure
functional-programming
ocaml
MaiaVictor
fonte
fonte
f x = 1
, o inverso de 1 é um conjunto de inteiros e o inverso de qualquer outra coisa é um conjunto vazio. Independentemente do que digam algumas respostas, a função não ser bijetiva não é o maior problema.f
é uma funçãog
quef . g = id
eg . f = id
. Seu candidato nem mesmo verifica nesse caso.f x = 1
não tem o inverso têm uma abordagem muito estreita e ignoram toda a complexidade do problema.Respostas:
Em alguns casos, sim! Há um belo artigo chamado Bidirecionalização de graça! que discute alguns casos - quando sua função é suficientemente polimórfica - onde é possível, de forma totalmente automática, derivar uma função inversa. (Também discute o que torna o problema difícil quando as funções não são polimórficas.)
O que você obtém no caso de sua função ser invertível é o inverso (com uma entrada espúria); em outros casos, você obtém uma função que tenta "mesclar" um valor de entrada antigo e um novo valor de saída.
fonte
put
funções em qualquer estrutura de registro derivandoData
: haskell.org/pipermail/haskell-cafe/2008-April/042193.html usando uma abordagem semelhante a que posteriormente apresentado (de forma mais rigorosa, mais geral, mais baseada em princípios, etc.) em "de graça".Não, geralmente não é possível.
Prova: considere funções bijetivas do tipo
com
Suponha que temos um inversor
inv :: F -> F
desse tipoinv f . f ≡ id
. Digamos que o tenhamos testado para a funçãof = id
, confirmando queComo esse primeiro
B0
na saída deve ter ocorrido depois de algum tempo finito, temos um limite superiorn
na profundidade para a qualinv
realmente avaliamos nossa entrada de teste para obter esse resultado, bem como o número de vezes que ela pode ter sido chamadaf
. Defina agora uma família de funçõesClaramente, para todos
0<j≤n
,g j
é uma bijeção, na verdade autoinversa. Portanto, devemos ser capazes de confirmarmas para cumprir isso,
inv (g j)
teria queg j (B1 : repeat B0)
a uma profundidade den+j > n
head $ g j l
pelo menos,n
listas diferentes correspondentesreplicate (n+j) B0 ++ B1 : ls
Até aquele ponto, pelo menos um dos
g j
é indistinguível def
, e uma vezinv f
que não tinha feito nenhuma dessas avaliações,inv
não poderia tê-lo diferenciado - além de fazer algumas medições de tempo de execução por conta própria, o que só é possível noIO Monad
.⬜
fonte
Você pode procurar na wikipedia, é chamado de Computação Reversível .
Em geral, você não pode fazer isso e nenhuma das linguagens funcionais tem essa opção. Por exemplo:
Esta função não possui inverso.
fonte
f
tem um inverso, mas o inverso é uma função não determinística?g :: Int -> a
que seja o inverso def
, mesmo que você possa descrever o inverso def
matematicamente.f x = 2 * x
serf' x = [x / 2]
, e então o inverso def _ = 1
éf' 1 = [minBound ..]; f' _ = []
. Ou seja, existem muitos inversos para 1 e nenhum para qualquer outro valor.Não na maioria das linguagens funcionais, mas na programação lógica ou na programação relacional, a maioria das funções que você define não são funções, mas "relações", e podem ser usadas em ambas as direções. Veja, por exemplo, prólogo ou kanren.
fonte
Tarefas como essa quase sempre são indecidíveis. Você pode ter uma solução para algumas funções específicas, mas não em geral.
Aqui, você nem consegue reconhecer quais funções têm um inverso. Citando Barendregt, HP The Lambda Calculus: Its Syntax and Semantics. North Holland, Amsterdam (1984) :
Vamos considerar A como o conjunto de termos lambda que representam funções invertíveis e B o resto. Ambos são não vazios e fechados sob igualdade beta. Portanto, não é possível decidir se uma função é invertível ou não.
(Isso se aplica ao cálculo lambda não digitado. TBH Não sei se o argumento pode ser adaptado diretamente a um cálculo lambda digitado quando sabemos o tipo de função que queremos inverter. Mas tenho certeza de que será semelhante.)
fonte
Se você pode enumerar o domínio da função e pode comparar os elementos do intervalo para igualdade, você pode - de uma maneira bastante direta. Por enumerar, quero dizer ter uma lista de todos os elementos disponíveis. Vou ficar com Haskell, já que não conheço Ocaml (ou mesmo como capitalizá-lo corretamente ;-)
O que você quer fazer é percorrer os elementos do domínio e ver se eles são iguais ao elemento do intervalo que você está tentando inverter e pegar o primeiro que funcione:
Já que você declarou que
f
é uma bijeção, deve haver um e apenas um desses elementos. O truque, é claro, é garantir que sua enumeração do domínio realmente alcance todos os elementos em um tempo finito . Se você está tentando inverter uma bijeção deInteger
paraInteger
, o uso[0,1 ..] ++ [-1,-2 ..]
não funcionará, pois você nunca obterá os números negativos. Concretamente,inv ([0,1 ..] ++ [-1,-2 ..]) (+1) (-3)
nunca renderá um valor.No entanto,
0 : concatMap (\x -> [x,-x]) [1..]
funcionará, visto que percorre os números inteiros na seguinte ordem[0,1,-1,2,-2,3,-3, and so on]
. Na verdadeinv (0 : concatMap (\x -> [x,-x]) [1..]) (+1) (-3)
retorna prontamente-4
!O pacote Control.Monad.Omega pode ajudá-lo a percorrer listas de tuplas, etc. de uma boa maneira; Tenho certeza de que há mais pacotes como esse - mas não os conheço.
Claro, essa abordagem é bastante simples e bruta, para não mencionar feia e ineficiente! Portanto, terminarei com algumas observações sobre a última parte da sua pergunta, sobre como 'escrever' bijeções. O sistema de tipos de Haskell não prova que uma função é uma bijeção - você realmente quer algo como Agda para isso - mas ele está disposto a confiar em você.
(Aviso: segue código não testado)
Então, você pode definir um tipo de dados de
Bijection
s entre os tiposa
eb
:junto com quantas constantes (onde você pode dizer 'Eu sei que são bijetivas!') quanto desejar, como:
e alguns combinadores inteligentes, como:
Acho que você poderia então fazer
invert (mapBi add1Bi) [1,5,6]
e obter[0,4,5]
. Se você escolher seus combinadores de maneira inteligente, acho que o número de vezes que terá que escrever umaBi
constante à mão pode ser bastante limitado.Afinal, se você sabe que uma função é uma bijeção, você terá um esboço de prova desse fato em sua cabeça, que o isomorfismo de Curry-Howard deve ser capaz de transformar em um programa :-)
fonte
Recentemente, tenho lidado com questões como essa e não, eu diria que (a) não é difícil em muitos casos, mas (b) não é nada eficiente.
Basicamente, suponha que você tenha
f :: a -> b
, e issof
é de fato uma bjiection. Você pode calcular o inversof' :: b -> a
de uma maneira realmente estúpida:Se
f
for uma bijeção eenumerate
realmente produzir todos os valores dea
, então você acabará atingindoa
tal quef a == b
.Tipos que possuem ae
Bounded
umaEnum
instância podem ser feitos trivialmenteRecursivelyEnumerable
. Pares deEnumerable
tipos também podem ser feitosEnumerable
:O mesmo vale para disjunções de
Enumerable
tipos:O fato de que podemos fazer isso para
(,)
eEither
provavelmente significa que podemos fazer para qualquer tipo de dados algébrico.fonte
Nem toda função possui um inverso. Se você limitar a discussão a funções um-para-um, a capacidade de inverter uma função arbitrária garante a capacidade de quebrar qualquer criptosistema. Esperamos que isso não seja viável, mesmo em teoria!
fonte
String encrypt(String key, String text)
sem a chave, você ainda não será capaz de fazer nada. EDIT: Além do que disse delnan.Em alguns casos, é possível encontrar o inverso de uma função bijetivo convertendo-a em uma representação simbólica. Com base neste exemplo , escrevi este programa Haskell para encontrar inversos de algumas funções polinomiais simples:
Este exemplo funciona apenas com expressões aritméticas, mas provavelmente poderia ser generalizado para funcionar com listas também.
fonte
Não, nem todas as funções têm inversos. Por exemplo, qual seria o inverso dessa função?
fonte