在 haskell 中加入两个 IOs 和 -

Join two IOs with - in haskell

我需要加入两个 IO String,中间有一个 -。这是我想出的,它有效 - 什么是正确的方法?

import System.Environment
f :: String -> String -> IO String
f x y = (foldl1 (++)) <$> sequence [(getEnv x),(return "-"),(getEnv y)]

连接两个 IO String 的一种方法是:

dash :: IO String -> IO String -> IO String
dash x y = do
    s1 <- x
    s2 <- y
    return $ s1 <> "-" <> s2

我们 "unbox" 每个 xy 得到包含的 Strings,然后用连字符“重新装箱”它们(使用 Functors 的类比) .

可以简写为:

dash = liftA2 (\s1 s2 -> s1 <> "-" <> s2)

其中 liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c 采用二元函数,"lifts" 将其转化为 Applicative 上的二元函数,MonadMonad 的超集。

然后您的 f 可以实现为 f x y = dash (getEnv x) (getEnv y)

您可以在此处使用应用样式函数:

f :: String -> String -> IO String
f x y = withHyp <$> getEnv x <*> getEnv y
    where withHyp ex ey = ex ++ '-' : ey

所以在这里我们连接两个 String,然后通过 withHyp 函数在中间连接一个连字符。

或者对于我们需要获取的环境变量列表,我们可以使用 mapM 并执行 intercalate:

import Data.List(intercalate)

f :: [String] -> IO String
f xs = intercalate "-" <$> mapM getEnv xs

老实说,你的方法背后的想法对我来说实际上看起来很理智。首先,我可能会使用 concat intsead of foldl1 (++),并删除一些括号,让我们:

f x y = concat <$> sequence [getEnv x, return "-", getEnv y]

这对我来说真的不是那么糟糕。但如果我真的想更进一步,我会有以下一些想法。首先,我会回忆一下 intercalate 函数。

f x y = intercalate "-" <$> sequence [getEnv x, getEnv y]

还有一个方便的 shorthand 可以将函数应用于列表的每个元素; mapM f = sequence . map f。所以:

f x y = intercalate "-" <$> mapM getEnv [x,y]

我会到此为止;对我来说它看起来很干净且易于维护。