Personnellement, je pense que ça devient un peu plus évident lorsque vous supprimez entre parenthèses redondantes de la le type (comme un non intrigant écrirait):
int -> (int -> bool -> int) -> bool -> int
Alors vous êtes censé écrire une fonction qui est donnée trois arguments et renvoie un int
. Autrement dit, une solution doit pouvoir être exprimée sous la forme suivante:
lambda n. lambda f. lambda b. ____
Mais comment remplir le trou? Eh bien, en regardant quels types vous obtenez à partir des paramètres, il est facile de voir que vous pouvez les brancher ensemble en appliquant f
à n
et b
, ce qui donne un int
. Donc:
lambda n. lambda f. lambda b. f n b
C'est une solution.Mais en regardant le terme soigneusement on remarque que le lambda le plus intérieur peut effectivement être réduite eta, donnant un terme encore plus simple:
lambda n. lambda f. f n
Mais en fait, la question est un dégénéré peu, parce que le retour d'un entier est toujours trivial . Donc, la solution est probablement plus simple:
lambda n. lambda f. lambda b. 0
Le régime général d'arriver à une solution est souvent par une simple induction sur la structure du type: si vous avez besoin d'une fonction, puis écrire un lambda et procéder récursive avec le corps. Si vous avez besoin d'un tuple, écrivez un tuple et continuez récursivement avec ses composants. Si vous avez besoin d'un type primitif, vous pouvez simplement choisir une constante. Si vous avez besoin de quelque chose que vous n'avez pas (habituellement dans le cas polymorphe), cherchez certains des paramètres de la fonction dans la portée qui vous donnerait une telle chose. Si ce paramètre est lui-même une fonction, essayez de construire récursivement un argument approprié.
J'ai une explication similaire sur les notes de cours de l'Université, mais elles ne semblent pas claires et sans code comme exemple. – Fedtekansler