我需要连接两个IO String
,中间有一个-
。这是我想出的,它有效 - 正确的方法是什么?
import System.Environment
f :: String -> String -> IO String
f x y = (foldl1 (++)) <$> sequence [(getEnv x),(return "-"),(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]
还有一个方便的速记,可以将函数应用于列表的每个元素; mapM f = sequence . map f
.所以:
f x y = intercalate "-" <$> mapM getEnv [x,y]
我会停在那里;对我来说,它看起来很干净,可以维护。
连接两个IO String
的一种方法是:
dash :: IO String -> IO String -> IO String
dash x y = do
s1 <- x
s2 <- y
return $ s1 <> "-" <> s2
我们"拆箱"x
和y
中的每一个,以获得包含的String
,然后用连字符"重新装箱"它们(使用函子的类比)。
它可以缩短为:
dash = liftA2 (s1 s2 -> s1 <> "-" <> s2)
其中liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
采用二进制函数并将其"提升"为Applicative
s上的二进制函数,这是Monad
s的超集。
然后,您的f
可以按f x y = dash (getEnv x) (getEnv y)
实现。