Je travaille à travers le 20 exercices de haskell intermédiaires pour le moment, ce qui est assez amusant exercer. Il implique la mise en œuvre de diverses instances du fonctionnement code> Foncteur code> et J'ai essayé de faire quelques De cela dans un style ponctuel, et je me demandais s'il y a un régime général pour transformer une définition point-ful (?) dans une définition sans points. Par exemple, voici le typeclass pour (les fonctions monad code> (et des fonctions qui prend
Foncteur code> s et
monad code> s arguments) mais avec des noms mignons comme
Furry code> et
brumeux code> pour dissimuler ce que nous faisons (fait un code intéressant).
Misty code>: p>
Unicorn code> et
banane code> sont
retour code> et
>> = code>, au cas où il ne serait pas évident) et voici mon implémentation de
Apple code> (équivalent à
Flip AP CODE>): P>
appleTurnover :: (Misty m) => m (a -> b) -> m a -> m b
appleTurnover = flip apple
banana1 :: (Misty m) => (a -> b) -> m a -> m b
banana1 = appleTurnover . unicorn
banana2 :: (Misty m) => (a -> b -> c) -> m a -> m b -> m c
banana2 f = appleTurnover . banana1 f
banana3 :: (Misty m) => (a -> b -> c -> d) -> m a -> m b -> m c -> m d
banana3 f x = appleTurnover . banana2 f x
banana4 :: (Misty m) => (a -> b -> c -> d -> e) -> m a -> m b -> m c -> m d -> m e
banana4 f x y = appleTurnover . banana3 f x y
5 Réponses :
Oui! L'une des astuces est d'écrire vos points dans la notation de préfixe plutôt que d'infixer. Ensuite, vous devriez être capable de trouver de nouvelles choses qui ressemblent à la composition de la fonction. Voici un exemple:
banana4 f x y = appleTurnover . banana3 f x y = (.) appleTurnover ((banana3 f x) y) = ((.) appleTurnover) . (banana3 f x) $ y banana4 f x = ((.) appleTurnover) . (banana3 f x) = (.) ((.) appleTurnover) (banana3 f x) = ((.) ((.) appleTurnover)) ((banana3 f) x) = ((.) ((.) appleTurnover)) . (banana3 f) $ x banana4 f = ((.) ((.) appleTurnover)) . (banana3 f) = (.) ((.) ((.) appleTurnover)) (banana3 f) = ((.) ((.) ((.) appleTurnover))) (banana3 f) = ((.) ((.) ((.) appleTurnover))) . banana3 $ f banana4 = ((.) ((.) ((.) appleTurnover))) . banana3 = (((appleTurnover .) .) .) . banana3
C'est également un bon moyen de rendre vos fonctions totalement illisibles, bien sûr ...
Donné retour code> est appelé
Unicorn code> il semble que l'OP n'est pas inquiet à propos de ça = p.
@Claudiu: Eh bien, ça vient des exercices que l'OP est en train de faire, qui dérivent fondamentalement des trucs comme monad code> à partir de la mise en place, en utilisant des noms très stupides pour les définitions.
Il y a un package PointeFree code> qui prend une définition de fonction HASKELLL et tente de ré-écrire dans un style
Pointefree code>. Je suggérerais d'expérimenter avec de nouvelles idées. Voir Cette page Pour plus de détails; Le colis est disponible ici . P>
Comme illustré par l'utilitaire code> PointPlare code>, il est possible de faire une telle conversion automatiquement. Cependant, le résultat est plus souvent obscurcié que l'amélioration. Si son objectif est d'améliorer la lisibilité plutôt que de le détruire, le premier objectif devrait être d'identifier pourquoi une expression a une structure particulière, trouvez une abstraction appropriée et construisez des choses de cette façon. P >
La structure la plus simple est simplement enchaînant des choses ensemble dans un pipeline linéaire, ce qui est une composition de fonction simple. Cela nous amène assez loin juste seul, mais comme vous l'avez remarqué, cela ne gère pas tout. P>
Une généralisation est de fonctionner avec des arguments supplémentaires, qui peuvent être construits progressivement. Voici un exemple: définir Une autre généralisation - qui englobe ce qui précède, réellement - est de définir les opérateurs qui appliquent une fonction à un composant d'une valeur plus grande. Un exemple ici serait Un cas légèrement différent est lorsque vous avez une fonction multi-arguments sur certains types C'est une question plus délicieuse lorsqu'un argument unique est utilisé plus d'une fois, mais il existe des modèles récurrents significatifs qui peuvent également être extraits. Un cas commun annonce ici appliquer plusieurs fonctions à un seul argument, puis collectionne les résultats avec une autre fonction. Ceci arrive à correspondre à l'instance code> d'application code> pour les fonctions, qui nous permet d'écrire des expressions telles que La chose importante, si vous souhaitez utiliser l'une d'entre elles en code réel, est de penser à ce que l'expression signifie em> et comment cela se reflète dans la structure. Si vous faites cela, puis le refactue dans le style pointut gratuit à l'aide de combinaisons significatifs, vous ferez souvent l'intention du code plus clair em> que ce n'en serait autrement, contrairement à la sortie typique de onresult = (. (.)) Code>. Maintenant, appliquer
Onresult code> N fois à une valeur initiale de
ID code> vous donne la composition de fonction avec le résultat d'une fonction N-ARY. Nous pouvons donc définir
comp2 = onresult (.) Code>, puis écrivez
comp2 non (&&) code> pour définir une opération NAND. P>
premier code> et
second code> dans
contrôler.arrow code>, qui fonctionne sur 2-tuples. Les combinaisons de rédaction sémantique sont basées sur cette approche. P>
B code> et une fonction
a -> b code> et devez les combiner dans un Fonction multi-arguments utilisant
A code>. Pour le cas commun des fonctions 2-ary, le module
data.function code> fournit le combinateur code> sur code>, que vous pouvez utiliser pour écrire des expressions telles que
comparer `on` fst code> pour comparer 2-tuples sur leurs premiers éléments. P>
(&&) <$> (> 3) <*> (<9) code> pour vérifier Si un numéro tombe dans une plage donnée. P>
PointPlare < / code>. p>
J'utilise le système de réécriture de trimestre suivant: Il est incomplet (lire pourquoi dans des livres sur la logique combinatoire), mais il suffit: P> Voici Banana2: p> réécrite en tant que lambda: p> écrire (.) dans le style préfixe: p> banana2 = ((.) appleTurnover) . banana1
Etant donné que le style Poinfree est le style des combinaisons, il suffit d'appliquer des définitions de combinaisons connues, les lire à l'envers pour effectuer la substitution: temps Souvent, à l'aide de sections de l'opérateur vous aide également: P> liftmx code>,
liftax code>,
séquence code>,
Sequencea code> peut simplifier les choses. J'envisageais aussi
pli dollar code>,
non enfoncé code>,
itérer code>,
jusqu'à code> comme des combinaisons de base. P>
((f .) . g) x y = f (g x y)
((. f) . g) x y = g x (f y)
(((f .) .) . g) x y z = (f .) (g x y) z = f (g x y z)
(((. f) .) . g) x y z = (. f) (g x y) z = g x y (f z)
Il est connecté à l'élimination de l'abstraction que vous faites pour transformer les expressions de calcul de Lambda en combinateurs. Vous voudrez peut-être également consulter l'autonome Outil PointFree (également disponible en tant que
@pl Code> dans Lambdabot ).
Une discussion connexe J'avais avec un ami l'autre jour . Vous pourriez le trouver intéressant.