haskell - optparse-applicative 与自定义 monad
问题描述
我正在尝试将我自己的 monad(而不是IO
)与customExecParser
https://hackage.haskell.org/package/optparse-applicative-0.15.1.0/docs/Options-Applicative-Extra.html#v:customExecParser一起使用。
所以我最终得到了(重要的功能是fff
):
data MoscConfig = MoscConfig {
datadir :: FilePath
, config :: FilePath
, pendingPath :: FilePath
, socket :: FilePath
}
type Mosco = StateT MoscConfig IO
main :: IO ()
main = join . customExecParser (prefs showHelpOnError) $
info (helper <*> parser)
( fullDesc
)
fff :: (a1 -> StateT MoscConfig IO a2) -> a1 -> IO a2
fff f = (flip evalStateT (MoscConfig "" "" "" "")) . f
xyzz :: Text -> Mosco ()
xyzz x = do
liftIO $ print x
liftIO $ print "testabcxyz"
xyzz' :: Text -> Text -> Mosco ()
xyzz' x x' = do
liftIO $ print x
liftIO $ print x'
liftIO $ print "testabcxyz"
parser :: Parser (IO ())
parser = do
fff xyzz <$> textOption ( long "zzz" )
<|>
((fmap fff) xyzz')
<$> textOption ( long "zzz" )
<*> textOption ( long "zzz" )
但是,上述方法的唯一缺点是fmap
需要所需的次数(匹配xyzz
or中的函数参数xyzz
)。我确实记得以前遇到过这类问题。有什么方法可以避免这种情况(并且只需要调用一个函数)?
理想情况下,我希望为此有一个 monad 转换器,但不幸的是,这似乎只能实现IO
。
解决方案
我认为这归结为一个问题:是否有一个功能fff
可以应用于两者:
xyzz :: a -> r
xyzz' :: a -> b -> r
以便:
fff xyzz :: a -> r'
fff xyzz' :: a -> b -> r'
答案是“不”,至少没有一些不值得考虑的类型类诡计。
相反,假设您的真实版本除了 compose 之外fff
实际上没有做任何事情f
,我想我会考虑写:
fff :: Parser (Mosco a) -> Parser (IO a)
fff = fmap $ flip evalStateT (MoscConfig "" "" "" "")
parser :: Parser (IO ())
parser = fff (xyzz <$> textOption ( long "zzz" ))
<|> fff (xyzz' <$> textOption ( long "zzz" ) <*> textOption ( long "zzz" ))
不过,这整个方法似乎有点“过时”。解析选项时你真的需要一个MoscConfig
可用的选项吗?除非您手头有一个非常复杂的选项解析问题,否则通常将选项直接解析为中间数据结构,然后针对该数据结构运行您的操作以修改状态并执行等等。Mosco
MoscConfig
IO
推荐阅读
- python - 为什么我不能在 selenium 中找到一个按钮?
- servlets - HTTP 状态 405 – Apache Tomcat 服务器中不允许的方法
- java - 从 Angular 前端到 Spring 后端的 POST 调用期间出现 CORS 策略错误
- r - 管道工在 R 中上传文件 csv
- php - 从 laravel 7 升级到 laravel 8
- ios - Xib 文件 UITableViewCell 出口为零
- mongodb - MongoDB Ops Manager 备份失败
- python - 根据行分组修改数据框并根据条件更新列
- apache-spark - 我可以在 PARTITION BY 中使用正则表达式吗?
- python - 什么是虚拟环境和目录,为什么要使用它们以及如何在我的系统中实现?