2010-12-02 18 views
19

De temps en temps je trébuche sur le problème que je veux exprimer "s'il vous plaît utiliser le dernier argument deux fois", par exemple. pour écrire un style sans point ou pour éviter un lambda. Par exemple.Astuce pour "réutiliser" des arguments dans Haskell?

sqr x = x * x 

pourrait être écrit comme

sqr = doubleArgs (*) where 
    doubleArgs f x = f x x 

Ou considèrent cette fonction un peu plus compliquée (prise de this question):

ins x xs = zipWith (\ a b -> a ++ (x:b)) (inits xs) (tails xs) 

Je pourrais écrire ce code Pointfree s'il y avait une fonction comme ce:

ins x = dup (zipWith (\ a b -> a ++ (x:b))) inits tails where 
    dup f f1 f2 x = f (f1 x) (f2 x) 

Mais comme je ne peux pas trouver quelque chose comme doubleArgs ou dup dans Hoogle, donc je suppose que je pourrais manquer un truc ou une idiome ici.

Répondre

26

De Control.Monad:

join :: (Monad m) -> m (m a) -> m a 
join m = m >>= id 

instance Monad ((->) r) where 
    return = const 
    m >>= f = \x -> f (m x) x 

expansion:

join :: (a -> a -> b) -> (a -> b) 
join f = f >>= id 
     = \x -> id (f x) x 
     = \x -> f x x 

Alors, oui, Control.Monad.join.

Oh, et pour votre exemple Pointfree, avez-vous essayé d'utiliser la notation applicative (de Control.Applicative):

ins x = zipWith (\a b -> a ++ (x:b)) <$> inits <*> tails 

(je aussi ne sais pas pourquoi les gens sont si friands de a ++ (x:b) au lieu de a ++ [x] ++ b ... ce n'est pas plus rapide - l'inliner va s'en occuper - et ce dernier est tellement plus symétrique!) Eh bien)

+2

Et d'après 'pointfree',' dup' serait 'liftM2'.J'ai vraiment besoin de mieux gérer l'instance de monad pour les fonctions. –

+2

Nous vous remercions tous les deux de vous donner même deux ** approches ** pour résoudre ces problèmes. BTW j'ai essayé '= SQR (*) <$> id <*> id' et il fonctionne aussi bien :-) – Landei

+0

' a ++ (x: b) 'est de 3 caractères plus courte que votre solution, peut-être pourquoi certaines personnes préfèrent? –

11

Ce que vous appelez 'doubleArgs' est plus souvent appelé dup - c'est le combinateur W dans To Mock a Mockingbird) - "le duplicateur élémentaire".

Ce que vous appelez 'dup' est en fait le combinateur 'starling-prime'. Haskell a une assez petite base de "combinator" voir Data.Function, plus quelques opérations Applicative et Monadic ajoutent plus de combinateurs "standard" en vertu des instances de fonction pour Applicative et Monad (< *> de Applicative est le S - combinateur d'étourneau pour l'instance fonctionnelle, liftA2 & liftM2 sont starling-prime). Il ne semble pas y avoir beaucoup d'enthousiasme dans la communauté pour l'expansion de Data.Function, alors même si les combinateurs sont amusants, pragmatiquement, je suis venu à préférer de loin dans les situations où un combinateur n'est pas directement disponible.

+2

Oh, j'ai trouvé les "oiseaux-opérateurs" pour Haskell: http://hackage.haskell.org/packages/archive/data-aviary/0.2.3/doc/html/Data-Aviary-Birds.html – Landei

+2

@Landei - Je les considère comme des "références seulement", c'est-à-dire que je ne recommanderais pas de les utiliser en fonction du code de travail. Je devrais rendre la description de la Cabale plus explicite, à savoir qu'ils ne sont que «référence», mais je ne m'en suis pas encore approché. –

+2

Qu'est-ce que @Landei appelle 'dup' est également connu comme [une « fourchette de verbe » dans J] (http://www.jsoftware.com/help/jforc/forks_hooks_and_compound_adv.htm), où il est écrit par la simple juxtaposition des opérateurs, par exemple '(f g h) x' au lieu de' dup f g h x'. –

7

Voici une autre solution pour la deuxième partie de ma question: Flèches!

import Control.Arrow 

ins x = inits &&& tails >>> second (map (x:)) >>> uncurry (zipWith (++)) 

Le &&& (« sortance ») distribue un argument à deux fonctions et retourne la paire des résultats. >>> ("et ensuite") inverse l'ordre d'application de la fonction, ce qui permet d'avoir une chaîne d'opérations de gauche à droite. second ne fonctionne que sur la deuxième partie d'une paire. Bien sûr, vous avez besoin d'un uncurry à la fin pour nourrir la paire dans une fonction qui attend deux arguments.