Je dois joindre deux IO String
s avec un -
entre les deux. Voici ce que j'ai trouvé, qui fonctionne - quelle est la bonne façon?
import System.Environment f :: String -> String -> IO String f x y = (foldl1 (++)) <$> sequence [(getEnv x),(return "-"),(getEnv y)]
3 Réponses :
Une façon de joindre deux chaînes d'E / S
serait:
dash = liftA2 (\s1 s2 -> s1 <> "-" <> s2)
Nous "déballons" chacun des x
et y
pour obtenir les String
s contenus, puis les «recadrer» avec un tiret (en utilisant l'analogie pour Functors).
Il peut être raccourci en: p>
dash :: IO String -> IO String -> IO String dash x y = do s1 <- x s2 <- y return $ s1 <> "-" <> s2
Où liftA2 :: Applicative f => (a -> b -> c) -> fa -> fb -> fc
prend une fonction binaire et le "lève" en une fonction binaire sur les Applicatifs
, qui sont un sur-ensemble de Monad
s.
Votre f code > peut alors être implémenté comme
fxy = dash (getEnv x) (getEnv y)
.
modifier la signature pour qu'elle corresponde à String -> String -> IO String
s'il vous plaît
Vous pouvez ici utiliser une fonction de style applicatif:
import Data.List(intercalate) f :: [String] -> IO String f xs = intercalate "-" <$> mapM getEnv xs
Nous joignons donc ici les deux String
qui sont ensuite jointes par un hypen au milieu via le Fonction withHyp
.
Ou pour une liste de variables d'environnement que nous devons récupérer, nous pouvons utiliser mapM
et effectuer une intercalation code>:
f :: String -> String -> IO String f x y = withHyp <$> getEnv x <*> getEnv y where withHyp ex ey = ex ++ '-' : ey
Je vais être honnête, l'idée derrière votre approche me semble en fait assez saine. Pour commencer, j'utiliserais probablement concat
intsead of foldl1 (++)
, et supprimerais quelques parenthèses, nous amenant à:
f x y = intercalate "-" <$> mapM getEnv [x,y]
Cela ne me semble vraiment pas si mal. Mais si je voulais vraiment aller plus loin, voici quelques réflexions que j'aurais. Tout d'abord, je rappelle la fonction intercaler
.
f x y = intercalate "-" <$> sequence [getEnv x, getEnv y]
Il existe également un raccourci pratique pour appliquer une fonction à chaque élément d'une liste; mapM f = séquence. carte f
. Donc:
f x y = concat <$> sequence [getEnv x, return "-", getEnv y]
Je m'arrêterais là; il me semble assez propre et facile à entretenir.
Juste une note pour OP à propos de concat
: foldl1 (++)
pour une liste de 3 éléments est évalué comme (a ++ b) ++ c code >, qui est légèrement plus lent que
a ++ (b ++ c)
en raison du passage de a
deux fois. Donc concat
est en fait implémenté comme quelque chose qui ressemble plus à foldr (++) []
(donnez ou prenez quelques différences de syntaxe)
Êtes-vous sûr que cela fonctionne comme vous le souhaitez? Cela me semble essentiellement équivalent à
f x y = getEnv x
(jusqu'à quelques absurdités avec le vôtre qui me lance peut-être des exceptions supplémentaires).non, ce n'est pas le cas. fixé.
encore plus laid maintenant!