Question fonctions Haskell simples dans un style sans point


J'essaie de comprendre comment convertir des fonctions en notation sans points dans Haskell. j'ai vu cet exemple, mais c'est plus compliqué que ce que je recherche. J'ai l'impression de comprendre la logique derrière cela, mais quand j'essaie d'exécuter des exemples simples dans le code, j'obtiens des erreurs de compilation. Je veux essayer d'écrire cette fonction dans un style sans points:

f x = 5 + 8/x que j'ai réarrangé comme f x = (+) 5 $ (/) 8 x

Donc, j'ai pensé que ça pourrait être quelque chose comme ça:

f = (+) 5 $ (/) 8

mais quand je lance ceci dans ghci je reçois ce message:

No instance for (Num (a0 -> a0))
  arising from the literal `5' at Test.hs:3:9
Possible fix: add an instance declaration for (Num (a0 -> a0))
In the first argument of `(+)', namely `5'
In the first argument of `($)', namely `(+) 5'
In the expression: (+) 5 $ (/) 8
Failed, modules loaded: none.

Je ne comprends pas le message "No instance for ...". Que dois-je faire pour écrire cette fonction dans un style sans points?


11
2017-12-11 16:34


origine


Réponses:


$ a une très faible priorité. Alors, f x = (+) 5 $ (/) 8 x signifie réellement f x = (+) 5 $ ((/) 8 x). Au lieu de cela, réécrire cela comme

f x = (+) 5 ( (/) 8 x)
f x = ((+) 5) ( ((/) 8) x)
f x = ((+) 5) .  ( ((/) 8) ) x
f = ((+) 5) . ( (/) 8 )
f = (5+) . (8/)

La dernière expression a un sens: f est la composition de deux opérations, divise d'abord 8 par ce que l'on a, puis ajoute 5 au résultat. Rappelles toi, g.h signifie "appliquer h, puis appliquer g le résultat de celui-ci".


17
2017-12-11 16:39



Le programme "pointfree" peut être installé avec cabal install pointfreeet vous montre comment écrire une expression sans style. Par exemple:

$ pointfree "f x = 5 + 8/x"
f = (5 +) . (8 /)

Explication de cette conversion:

  1. Vous pouvez utiliser des "sections" pour les fonctions infixes / opérateurs. (a +) == \b -> a + b et (+ a) == \b -> b + a
  2. le . function prend le résultat du second paramètre, qui est une fonction à un argument, et l'applique au premier argument.

11
2017-12-11 16:43



Conversion de lambda-calcul (dont Haskell est une variante de) termes en termes SKI (fonctions totalement libres de points, utilisant uniquement const (K), id (je) et <*> (S)) peut être fait avec les règles simples suivantes:

  1. \x -> x Se traduit par id;
  2. \x -> y sans pour autant x se produisant dans y Se traduit par const y;
  3. \x -> f g Se traduit par f' <*> g' où
    • f' est une traduction de \x -> f et
    • g' est une traduction de \x -> g.

Maintenant, vous pouvez vous demander où est la . entrez. Il y a un cas particulier de la dernière traduction: si f n'a pas d'occurrences gratuites de x, puis \x -> f g Se traduit par const f <*> (\x -> g), qui est égal à f . (\x -> g).

En utilisant ces règles, nous pouvons convertir votre fonction:

f = \x -> ((+) 5) (((/) 8) x) = -- by the special-case (.) rule
((+) 5) . (\x -> (((/) 8) x)) = -- by eta-reduction ((\x -> f x) = f)
((+) 5) . ((/) 8)

Eta-reduction n'est pas nécessaire pour compléter la traduction, mais sans cela, nous aurions quelque chose de plus désordonné. Par exemple, la dernière étape donnerait ((+) 5) . ((/) 8) . id au lieu.


11
2017-12-11 23:01



Tu étais vraiment proche. Permettez-moi d'ajouter un autre $ pour illustrer:

f x = (+) 5 $ (/) 8 $ x

Il devrait être clair que l'expression (+) 5 est une fonction qui prend une entrée numérique et produit une sortie numérique. La même chose vaut pour l'expression (/) 8. Donc, vous prenez le nombre qui est entré, x, et d'abord appliquer le (/) 8 "fonction", puis appliquer le (+) 5 "fonction".

Chaque fois que vous avez une chaîne de fonctions séparée par $, vous pouvez remplacer tous sauf le plus à droite avec . Signification, si vous avez a $ b $ c $ d, cela équivaut à a . b . c $ d.

f x = (+) 5 . (/) 8 $ x

À ce stade, faisons retirer la $ et entre parenthèses à la place.

f x = ((+) 5 . (/) 8) x

Maintenant, il devrait être clair que vous pouvez supprimer le suivi x des deux côtés:

f = (+) 5 . (/) 8

Cette est l'idée principale. Si tu as f x = expr x, vous pouvez "le réduire" à f = expr. Afin de produire un code sans point, il vous suffit de reconnaître comment la fonction plus grande est composée de fonctions plus petites. Une application partielle est parfois nécessaire pour un code sans point (comme dans ce cas, (+) 5 et (/) 8 sont partiellement appliquées). Le programme "sans points" est très utile lorsque vous ne voulez pas y penser; Lambdabot sur le canal irc #haskell utilise ce programme comme un plugin, vous n'avez donc même pas besoin de l'installer vous-même; il suffit de demander:

<DanBurton> @pl let f x = 5 + 8 / x in f
<lambdabot> (5 +) . (8 /)

4
2017-12-11 22:56