En Haskell performance `et` et `ou` pour les fonctions booléennes
J'ai juste écrit les deux fonctions suivantes:
fand :: (a -> Bool) -> (a -> Bool) -> a -> Bool
fand f1 f2 x = (f1 x) && (f2 x)
f_or :: (a -> Bool) -> (a -> Bool) -> a -> Bool
f_or f1 f2 x = (f1 x) || (f2 x)
Ils pourraient être utilisés pour combiné les valeurs de deux booléens fonctions telles que:
import Text.ParserCombinators.Parsec
import Data.Char
nameChar = satisfy (isLetter `f_or` isDigit)
D'après ces deux fonctions, je suis venu à réaliser qu'elles sont très utiles. tant et si bien que maintenant, je soupçonne qu'ils sont soit inclus dans la bibliothèque standard, ou, plus probablement, qu'il y a un moyen propre de faire cela à l'aide de fonctions existantes.
Ce qu'était la "bonne" façon de le faire?
- Haskell, la langue où tout est déjà dans un typeclass de la bibliothèque standard, quelque part. Typeclassopedia peut aider à remédier à cela.
Vous devez vous connecter pour publier un commentaire.
Une simplification,
ou
dans le
((->) r)
foncteur applicatif.Applicative version
Pourquoi? Nous avons:
Donc:
Monade version
Ou pour
liftM2
, nous avons:donc:
Monad
exemple, mais il est agréable de travailler à travers. Ma première hypothèse étaiton
... obtenu qu'un type de vers l'arrière.liftA2
au lieu deliftM2
.Totalement arrachant de TomMD, j'ai vu le
and . map
etor . map
et ne pouvait pas aider mais veulent ruser:Ces lire bien je pense.
fAnd
: toutes les fonctions sont dans la listeTrue
quandx
est appliqué à eux?fOr
: sont toutes les fonctions dans la listeTrue
quandx
est appliqué à eux?est un drôle de nom, mais. Certainement un bon à jeter ceux impératif programmeurs pour un boucle. =)
all
etany
?!fAnd [even, odd] 3
est beaucoup mieux queall ($3) [even, odd]
bien .filter (`any` [even, prime]) . flip ($)) xs
Il est plus laid si vous voulez toujours deux fonctions, mais je pense que je ferais généraliser ce:
($x)
utilisé en Haskell. Pendant une seconde j'ai cru que j'étais de retour en PHP terre frissonner.(\f -> f x)
Sur le dessus de ce qui Ne l'a dit, le
liftA2/liftM2
versions peuvent ne pas être paresseux assez:>
let a .&&. b = liftA2 (&&) a b in pure False .&&. undefined
*** Exception: Prelude.undefined
Oups!
Donc, au lieu de cela, vous pourriez vouloir un peu différente de la fonction. Notez que cette nouvelle fonction nécessite un
Monad
contrainte --Applicative
est insuffisante.>
let a *&&* b = a >>= \a' -> if a' then b else return a' in pure False *&&* undefined
False
C'est mieux.
Que la réponse que suggère le
on
fonction, c'est pour quand les fonctions sont les mêmes, mais les arguments sont différents. Dans votre cas, les fonctions sont différentes, mais les arguments sont les mêmes. Ici est votre exemple modifiées de sorte que leson
est une réponse appropriée:(f x) && (f y)
qui peut être écrit:
on (&&) f x y
PS: les parenthèses sont inutiles.
let a .&&. b = liftA2 (&&) a b in (pure False .&&. undefined) ()
f <*> a
les effets secondairesf
avoir lieu avant les effets secondairesa
. Mais le lecteur monade n'a pas d'effets secondaires, de sorte qu'il peut ignorer les calculs à partir duquel les résultats ne sont pas nécessaires.Cela peut aussi être fait en utilisant Flèches:
&&&
(non liée à&&
) divise l'entrée;>>>
est flèche/catégorie composition.Voici un exemple:
Cela fonctionne parce que les fonctions --
->
-- sont des instances de la Catégorie et de la Flèche. En comparant le type de signatures N'estliftA2
etliftM2
exemples montre les similitudes:Outre le nourrissage, notez que vous pouvez pratiquement convertir le premier type dans la seconde, par la substitution
cat a ---> f
etArrow ---> Applicative
(l'autre différence est quesplit_combine
n'est pas limitée à la prise de fonctions pures dans son 1er argument; probablement pas important tout de même).Cela a sortof été mentionné, mais de façon plus complexe. Vous pouvez utiliser applicative de trucs.
Pour des fonctions essentiellement, ce qu'il fait est de passer le même argument à un certain nombre de fonctions que vous pouvez combiner à la fin.
De sorte que vous pourriez mettre en œuvre comme ceci:
Pour chaque
<*>
de la chaîne, puis vous obtenez une autre fonction qui s'applique à un, puis vous munge la sortie ensemble à l'aide defmap
alternativement écrit comme<$>
. La raison pour laquelle cela fonctionne avec&&
est parce qu'il prend deux arguments et nous avons 2 fonctions joué ensemble. Si il y a un supplément de star là-bas et une autre case que vous devriez écrire quelque chose comme:check this out pour plus d'exemples
(&&) <$> aChekOnA <*> anotherCheckOnA $ a
?Si f1 et f2 sont les mêmes, alors vous pouvez utiliser le "on":
dans la base de Données.Fonction
Utilisation typique:
(à partir de Hoogle)
all
etany
), plutôt que des fonctions multiples contre une seule valeur.