Je ne prétends pas comprendre cela du tout, mais si cela peut aider quelqu'un... alors youpi.
Considérons la définition de fix
. fix f = let x = f x in x
. Ce qui est le plus étonnant, c'est que x
est défini comme suit f x
. Mais réfléchissez-y un instant.
x = f x
Puisque x = f x, nous pouvons substituer la valeur de x
sur le côté droit, n'est-ce pas ? Donc...
x = f . f $ x -- or x = f (f x)
x = f . f . f $ x -- or x = f (f (f x))
x = f . f . f . f . f . f . f . f . f . f . f $ x -- etc.
L'astuce consiste donc à mettre un terme à la procédure, f
doit générer une sorte de structure, de sorte qu'un f
peut faire une correspondance avec cette structure et mettre fin à la récursion, sans se soucier de la "valeur" complète de son paramètre ( ?).
Sauf, bien sûr, si vous souhaitez créer une liste infinie, comme l'a illustré luqui.
L'explication factorielle de TomMD est bonne. La signature de type de Fix est (a -> a) -> a
. La signature de type pour (\recurse d -> if d > 0 then d * (recurse (d-1)) else 1)
es (b -> b) -> b -> b
en d'autres termes, (b -> b) -> (b -> b)
. On peut donc dire que a = (b -> b)
. De cette façon, fix prend notre fonction, qui est a -> a
ou vraiment, (b -> b) -> (b -> b)
et renvoie un résultat du type a
en d'autres termes, b -> b
En d'autres termes, une autre fonction !
Attendez, je pensais qu'il était censé retourner un point fixe... et non une fonction. Et bien c'est le cas, en quelque sorte (puisque les fonctions sont des données). Vous pouvez imaginer qu'il nous a donné la fonction définitive pour trouver une factorielle. Nous lui avons donné une fonction qui ne savait pas comment réintégrer (c'est pourquoi l'un de ses paramètres est une fonction utilisée pour réintégrer), et fix
lui a appris la récursivité.
Vous vous souvenez que j'ai dit que f
doit générer une sorte de structure afin qu'un futur f
peut-elle correspondre à un modèle et se terminer ? Ce n'est pas tout à fait exact, je suppose. TomMD a illustré la façon dont nous pouvons étendre x
pour appliquer la fonction et se rapprocher du cas de base. Pour sa fonction, il a utilisé un if/then, et c'est ce qui provoque la terminaison. Après des remplacements répétés, le in
partie de l'ensemble de la définition de fix
finit par ne plus être défini en termes de x
et c'est à ce moment-là qu'il est calculable et complet.
78 votes
La réponse de la farce est "le fixe n'a pas d'utilité réelle, il est juste là pour que vous puissiez taper".
fix error
dans le ghci et se sentir bien dans sa peau".5 votes
@TomMD - C'est drôle. Je m'en souviendrai si quelqu'un me demande ce que fait fix et que je me sens mal à l'aise :-)
5 votes
J'écris généralement
fix
commefix f = f (fix f)
. Court, simple, efficace et identique à la définition mathématique.21 votes
@newacct, oui c'est aussi comme ça que je vois les choses. Mais celle qui est proposée ici peut conduire à des structures plus efficaces. Vous pouvez voir la différence si vous évaluez, disons,
fix (1:) !! (10^8)
. L'original le fait en mémoire constante, le vôtre prend de la mémoire linéaire (ce qui le rend aussi un peu plus lent). En d'autres termes, l'utilisation de let "fait un nœud plus serré" et permet de générer une structure de données circulaire, ce qui n'est pas le cas de la vôtre.33 votes
Vous auriez pu réinventer
fix
aussi ! m'a aidé à comprendrefix
beaucoup.2 votes
Le lien de @fredoverflow est la MEILLEURE explication. Tout le reste m'embrouille.