Dans les langages fonctionnels purs comme Haskell, existe-t-il un algorithme pour obtenir l'inverse d'une fonction, (modifier) quand elle est bijective? Et y a-t-il une manière spécifique de programmer votre fonction ainsi?
haskell
clojure
functional-programming
ocaml
MaiaVictor
la source
la source
f x = 1
, l'inverse de 1 est un ensemble d'entiers et l'inverse de toute autre chose est un ensemble vide. Indépendamment de ce que disent certaines réponses, la fonction n'étant pas bijective n'est pas le plus gros problème.f
est une fonctiong
telle quef . g = id
etg . f = id
. Votre candidat ne vérifie même pas la typographie dans ce cas.f x = 1
n'y a pas d'inverse adoptent une approche très étroite et ignorent toute la complexité du problème.Réponses:
Dans certains cas, oui! Il existe un beau papier appelé Bidirectionalization for Free! qui traite de quelques cas - lorsque votre fonction est suffisamment polymorphe - où il est possible, de manière complètement automatique, de dériver une fonction inverse. (Il discute également de ce qui rend le problème difficile lorsque les fonctions ne sont pas polymorphes.)
Ce que vous obtenez dans le cas où votre fonction est inversible est l'inverse (avec une entrée fausse); dans d'autres cas, vous obtenez une fonction qui essaie de "fusionner" une ancienne valeur d'entrée et une nouvelle valeur de sortie.
la source
put
fonctions dans toutes les structures d'enregistrement dérivantData
: haskell.org/pipermail/haskell-cafe/2008-April/042193.html en utilisant une approche similaire à que plus tard présenté (plus rigoureusement, plus généralement, plus raisonné, etc.) dans «gratuitement».Non, ce n'est pas possible en général.
Preuve: considérez les fonctions bijectives de type
avec
Supposons que nous ayons un onduleur
inv :: F -> F
tel queinv f . f ≡ id
. Disons que nous l'avons testé pour la fonctionf = id
, en confirmant quePuisque ce premier
B0
dans la sortie doit être venu après un temps fini, nous avons une limite supérieuren
à la fois sur la profondeur à laquelleinv
avait réellement évalué notre entrée de test pour obtenir ce résultat, ainsi que sur le nombre de fois qu'il a pu appelerf
. Définissez maintenant une famille de fonctionsClairement, pour tous
0<j≤n
,g j
est une bijection, en fait auto-inverse. On devrait donc pouvoir confirmermais pour y parvenir,
inv (g j)
il aurait fallu soitg j (B1 : repeat B0)
à une profondeur den+j > n
head $ g j l
pour au moinsn
différentes listes correspondantesreplicate (n+j) B0 ++ B1 : ls
Jusque-là, au moins une des évaluations
g j
est indiscernable def
, et depuisinv f
n'a fait aucune de ces évaluations,inv
n'aurait pas pu la distinguer - à moins de faire certaines mesures d'exécution par elle-même, ce qui n'est possible que dans leIO Monad
.⬜
la source
Vous pouvez le rechercher sur wikipedia, il s'appelle Reversible Computing .
En général, vous ne pouvez pas le faire et aucun des langages fonctionnels n'a cette option. Par exemple:
Cette fonction n'a pas d'inverse.
la source
f
cela a un inverse, c'est juste que l'inverse est une fonction non déterministe?g :: Int -> a
qui soit l'inverse def
, même si vous pouvez décrire l'inverse def
mathématiquement.f x = 2 * x
bef' x = [x / 2]
, puis l'inverse def _ = 1
isf' 1 = [minBound ..]; f' _ = []
. Autrement dit, il existe de nombreux inverses pour 1 et aucun pour toute autre valeur.Pas dans la plupart des langages fonctionnels, mais dans la programmation logique ou la programmation relationnelle, la plupart des fonctions que vous définissez ne sont en fait pas des fonctions mais des «relations», et celles-ci peuvent être utilisées dans les deux sens. Voir par exemple prolog ou kanren.
la source
Des tâches comme celle-ci sont presque toujours indécidables. Vous pouvez avoir une solution pour certaines fonctions spécifiques, mais pas en général.
Ici, vous ne pouvez même pas reconnaître quelles fonctions ont un inverse. Citant Barendregt, HP Le calcul Lambda: sa syntaxe et sa sémantique. Hollande du Nord, Amsterdam (1984) :
Prenons A pour l'ensemble des termes lambda qui représentent des fonctions inversibles et B le reste. Les deux sont non vides et fermés sous l'égalité bêta. Il n'est donc pas possible de décider si une fonction est inversible ou non.
(Cela s'applique au calcul lambda non typé. TBH Je ne sais pas si l'argument peut être directement adapté à un calcul lambda typé lorsque nous connaissons le type de fonction que nous voulons inverser. Mais je suis presque sûr que ce sera similaire.)
la source
Si vous pouvez énumérer le domaine de la fonction et comparer les éléments de la plage pour l'égalité, vous pouvez - d'une manière assez simple. Par énumérer, j'entends avoir une liste de tous les éléments disponibles. Je m'en tiens à Haskell, car je ne connais pas Ocaml (ni même comment le capitaliser correctement ;-)
Ce que vous voulez faire, c'est parcourir les éléments du domaine et voir s'ils sont égaux à l'élément de la plage que vous essayez d'inverser, puis prenez le premier qui fonctionne:
Puisque vous avez déclaré que
f
c'est une bijection, il y a forcément un et un seul élément de ce type. L'astuce, bien sûr, est de vous assurer que votre énumération du domaine atteint réellement tous les éléments dans un temps fini . Si vous essayez d'inverser une bijection deInteger
enInteger
, l'utilisation[0,1 ..] ++ [-1,-2 ..]
ne fonctionnera pas car vous n'obtiendrez jamais les nombres négatifs. Concrètement,inv ([0,1 ..] ++ [-1,-2 ..]) (+1) (-3)
ne donnera jamais de valeur.Cependant,
0 : concatMap (\x -> [x,-x]) [1..]
cela fonctionnera, car cela parcourt les entiers dans l'ordre suivant[0,1,-1,2,-2,3,-3, and so on]
. En effetinv (0 : concatMap (\x -> [x,-x]) [1..]) (+1) (-3)
revient rapidement-4
!Le package Control.Monad.Omega peut vous aider à parcourir des listes de tuples, etc. d'une bonne manière; Je suis sûr qu'il y a plus de paquets comme ça - mais je ne les connais pas.
Bien sûr, cette approche est plutôt discrète et brutale, pour ne pas mentionner laide et inefficace! Je terminerai donc par quelques remarques sur la dernière partie de votre question, sur la manière d '«écrire» des bijections. Le système de types de Haskell n'est pas à la hauteur de prouver qu'une fonction est une bijection - vous voulez vraiment quelque chose comme Agda pour cela - mais il est prêt à vous faire confiance.
(Attention: le code non testé suit)
Alors pouvez-vous définir un type de données de
Bijection
s entre les typesa
etb
:avec autant de constantes (où vous pouvez dire `` Je sais que ce sont des bijections! '') que vous le souhaitez, telles que:
et quelques combinateurs intelligents, tels que:
Je pense que vous pourriez alors faire
invert (mapBi add1Bi) [1,5,6]
et obtenir[0,4,5]
. Si vous choisissez vos combinateurs de manière intelligente, je pense que le nombre de fois que vous devrez écrire uneBi
constante à la main pourrait être assez limité.Après tout, si vous savez qu'une fonction est une bijection, vous aurez, espérons-le, un croquis de preuve de ce fait dans votre tête, que l'isomorphisme de Curry-Howard devrait pouvoir transformer en programme :-)
la source
J'ai récemment été confronté à des problèmes comme celui-ci, et non, je dirais que (a) ce n'est pas difficile dans de nombreux cas, mais (b) ce n'est pas du tout efficace.
Fondamentalement, supposons que vous ayez
f :: a -> b
, et c'est enf
effet une bjiection. Vous pouvez calculer l'inversef' :: b -> a
d'une manière vraiment stupide:Si
f
est une bijection etenumerate
produit vraiment toutes les valeurs dea
, alors vous finirez par frapper unea
telle chosef a == b
.Les types qui ont un
Bounded
et uneEnum
instance peuvent être créés de manière simpleRecursivelyEnumerable
. Des paires deEnumerable
types peuvent également être réaliséesEnumerable
:Il en va de même pour les disjonctions de
Enumerable
types:Le fait que nous puissions le faire à la fois pour
(,)
etEither
signifie probablement que nous pouvons le faire pour n'importe quel type de données algébriques.la source
Toutes les fonctions n'ont pas d'inverse. Si vous limitez la discussion à des fonctions individuelles, la possibilité d'inverser une fonction arbitraire donne la possibilité de casser n'importe quel cryptosystème. Nous devons en quelque sorte espérer que ce n'est pas faisable, même en théorie!
la source
String encrypt(String key, String text)
sans la clé, vous ne pourrez toujours rien faire. EDIT: Plus ce que Delnan a dit.Dans certains cas, il est possible de trouver l'inverse d'une fonction bijective en la convertissant en une représentation symbolique. Sur la base de cet exemple , j'ai écrit ce programme Haskell pour trouver les inverses de certaines fonctions polynomiales simples:
Cet exemple ne fonctionne qu'avec des expressions arithmétiques, mais il pourrait probablement être généralisé pour fonctionner également avec des listes.
la source
Non, toutes les fonctions n'ont même pas d'inverses. Par exemple, quel serait l'inverse de cette fonction?
la source