【发布时间】:2019-08-06 06:31:16
【问题描述】:
我正在尝试编写一个模块,该模块允许从任意来源(例如,内存列表,或文件,数据库......等等)获取字符串:
type StringFetcher m = String -> m String
listStringFetcher :: [(String, String)] -> StringFetcher Maybe
listStringFetcher list key = fst <$> (listToMaybe $ filter ((key ==) . fst) list)
fileStringFetcher :: FilePath -> StringFetcher (MaybeT IO)
fileStringFetcher fp key = undefined
然后我想当我在我的应用程序中使用它时,我可以拥有如下功能:
usage :: (MonadIO m) => StringFetcher m -> m ()
usage fetch = (fetch "usage") >>= (liftIO . putStrLn)
但后来我有点卡住了,当我尝试运行 usage (listStringFetcher [("usage", "asdf")]) 时,我得到一个“由于使用 usage 而导致(MonadIO Maybe)没有实例”错误。我不太确定我应该如何访问StringFetcher 的“内部”字符串。所以我觉得这种方法可能不可行。有没有更合理的方法来做这样的事情?
编辑:为了更清楚地说明我想要实现的目标,这是我的应用程序中的一个实际功能:
usage :: [Command] -> ExceptT String IO String
usage c = pure . ununlines $ [
"usage: xyz <command>",
"Commands:",
unlines $ fmap (\x ->"\t" ++ name (x :: Command) ++ ": " ++ description (x :: Command)) c
]
我不想像这样硬编码字符串"usage: xyz <command>" 和"Commands:"。我想做的是向函数添加另一个参数,其工作是使用键获取这些字符串。但我希望可以将“String fetcher”与不同的实现(可能涉及也可能不涉及 IO)互换。
【问题讨论】:
-
I'm not quite sure how I'm supposed to get access to the string "inside" of the StringFetcher.- 如果我对您的理解正确,那么您通常不能。没有一般的方法可以访问 Monad “内部”的值。我不太确定fetch的意图是什么,我知道硬编码的"usage"只是为了说明,但是除非这是您将使用几次的一般模式,否则编写函数是没有意义的,在在哪种情况下该怎么做取决于你如何使用它,这对我来说并不清楚。 -
PS in
listStringFetcher我想你希望外部的fst是snd -
这是我想在多个地方使用的一般模式。这个想法是从“任何地方”获取字符串以在程序中使用。我的想法被赋予了
StringFetcher的类型,我应该可以将它与任何 monad 一起使用,并在该 monad 中使用>>=(和朋友)对字符串做一些有用的事情。 -
明确地说,我根本不接受这种方法。或者,也许我在想整个事情是完全错误的。目标是拥有可以提供任意 StringFetcher 的函数。