La fusion/Ajoutez Justs en Haskell
-
13-11-2019 - |
Question
Je suis en train de faire ce qui doit être évidentes en Haskell, qui est d'aller d' Just [1]
et Just [2]
pour Just [1, 2]
.Cependant je ne peux pas trouver quelque chose en ligne que je continue de trouver un lien mais inutile pages.Alors, comment voulez-vous accomplir cela?
La solution
Vous pouvez utiliser liftA2 (++)
:
liftA2 (++) :: Maybe [a] -> Maybe [a] -> Maybe [a]
liftA2
juste des ascenseurs une fonction binaire dans un Applicative
. Applicative
s ont été conçus pour le levage de fonctions arbitraires d'arguments dans un contexte, donc ils sont parfaits pour cela.Dans ce cas, l' Applicative
nous utilisons est Maybe
.Pour voir comment cela fonctionne, nous pouvons regarder la définition:
liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b
(<$>)
juste ascenseurs toute fonction sur de pures valeurs de fonctionnement à l'intérieur de f
: (a -> b) -> f a -> f b
.(C'est juste un alias pour fmap
, si vous êtes familier avec Functor
s). Pour Maybe
:
_ <$> Nothing = Nothing
f <$> Just x = Just (f x)
(<*>)
c'est un peu plus compliqué:il applique une fonction à l'intérieur de f
pour une valeur à l'intérieur f
: f (a -> b) -> f a -> f b
.Pour Maybe
:
Just f <*> Just x = Just (f x)
_ <*> _ = Nothing
(En fait, f <$> x
c'est la même chose que pure f <*> x
, qui est Just f <*> x
pour Maybe
.)
Donc, on peut étendre la définition de l' liftA2 (++)
:
liftA2 (++) a b = (++) <$> a <*> b
-- expand (<$>)
liftA2 (++) (Just xs) b = Just (xs ++) <*> b
liftA2 (++) _ _ = Nothing
-- expand (<*>)
liftA2 (++) (Just xs) (Just ys) = Just (xs ++ ys)
liftA2 (++) _ _ = Nothing
En effet, nous pouvons utiliser ces opérateurs pour soulever une fonction de tout nombre d'arguments dans n'importe quel Applicative
, juste en suivant le schéma de liftA2
.Ceci est appelé applicative style, et est très commun dans idiomatiques du code Haskell.Dans ce cas, il pourrait même être plus idiomatique de l'utiliser directement en écrivant (++) <$> a <*> b
, si a
et b
sont déjà variables.(D'un autre côté, si vous êtes partiellement l'application il — dire, de les transmettre à une fonction d'ordre supérieur — puis liftA2 (++)
est préférable.)
Chaque Monad
est un Applicative
, donc si jamais vous vous trouvez en essayant de "lever" une fonction dans un contexte, Applicative
est probablement ce que vous cherchez.
Autres conseils
Pour étendre la solution à une liste de Just
s, vous pouvez utiliser
fmap join $ sequence [Just[1],Just[2],Just[3]]
-- Just [1,2,3]
alors que @ehird la réponse est génial, je l'aurais utilisé une noobish solution sous la forme:
mergeJust a b = do
a' <- a
b' <- b
return (a' ++ b')
Depuis, il n'a pas été mentionné dans d'autres solutions, je vais le dire ici.La façon la plus simple pour accomplir votre tâche, à mon avis, est d'utiliser un <>
(ou mappend
) de Data.Monoid
.
import Data.Monoid
Just [1,2] <> Just [7,8] == Just [1,2,7,8]
Toutefois, notez que cette solution, contrairement à ehird de la solution applicative, ne seront pas court-circuit sur Nothing
des valeurs.
Just [1,2] <> Nothing ---> Just [1,2]
--However
(++) <$> Just [1,2] <*> Nothing ---> Nothing