4
votes

Rejoignez deux IO avec - dans haskell

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 commentaires

Ê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!


3 Réponses :


4
votes

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

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 Monads.

Votre f code > peut alors être implémenté comme fxy = dash (getEnv x) (getEnv y) .


1 commentaires

modifier la signature pour qu'elle corresponde à String -> String -> IO String s'il vous plaît



7
votes

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


0 commentaires

6
votes

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.


1 commentaires

Juste une note pour OP à propos de concat : foldl1 (++) pour une liste de 3 éléments est évalué comme (a ++ b) ++ c , 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)