haz*_*haz 1 monads haskell maybe
我有一个Request类型:
data Request =
Request {
reqType :: RequestType,
path :: String,
options :: [(String, String)]
} deriving Show
Run Code Online (Sandbox Code Playgroud)
我正在解析它(来自原始HTTP请求),如下所示:
parseRawRequest :: String -> Request
parseRawRequest rawReq =
Request {
reqType = parseRawRequestType rawReq,
path = parseRawRequestPath rawReq,
options = parseRawRequestOps rawReq
}
Run Code Online (Sandbox Code Playgroud)
现在,在两个电话parseRawRequestType,parseRawRequestPath(等)可能会失败.为了使我的代码更具弹性,我改变了他们的类型签名:
parseRawRequestType :: String -> RequestType
Run Code Online (Sandbox Code Playgroud)
至
parseRawRequestType :: String -> Maybe RequestType
Run Code Online (Sandbox Code Playgroud)
但是parseRawRequest变成一个最好的方法是Maybe Request什么?我必须手动检查每个部件(reqType,path,options)的Nothing,或者是有我就是缺少一个不同的方式?
必须有办法以某种方式组成对象创建和Nothing检查!
我写了以下内容,但感觉很乱并且不理想:(未经测试)
parseRawRequest :: String -> Maybe Request
parseRawRequest rawReq
| Nothing `elem` [reqType, path, options] = Nothing
| otherwise =
Just Request { reqType=reqType, path=path, options=options }
where reqType = parseRawRequestType rawReq
path = parseRawRequestPath rawReq
options = parseRawRequestOps rawReq
Run Code Online (Sandbox Code Playgroud)
干杯.
这正是Applicative Functors(Control.Applicative)所代表的模式.Applicative就像普通的Functors,但有两个额外的操作:
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)
pure允许你将任何值放入应用程序中,这意味着对于任何应用程序,你可以写一个fmapas fmap f x = pure f <*> x.
在这种情况下,有趣的运算符是<*>.这个想法是,如果你在函数"里面"有一个函数,你可以将它应用到仿函数中的另一个值.如果你这样做Request <$> (_ :: Maybe RequestType),你会得到一些类型的东西Maybe (String -> [(String, String)] -> Request).然后,<*>操作员将允许您将其应用于某种类型Maybe String以获取Maybe [(String, String)] -> Request)等等.
例:
data RequestType
data Request =
Request { reqType :: RequestType, path :: String, options :: [(String, String)] }
parseRawRequestType :: String -> Maybe RequestType
parseRawRequestType = undefined
parseRawRequestPath :: String -> Maybe String
parseRawRequestPath = undefined
parseRawRequestOps :: String -> Maybe [(String, String)]
parseRawRequestOps = undefined
parseRawRequest :: String -> Maybe Request
parseRawRequest rawReq = Request <$> parseRawRequestType rawReq
<*> parseRawRequestPath rawReq
<*> parseRawRequestOps rawReq
Run Code Online (Sandbox Code Playgroud)
但请注意,应用的函数必须具有类型f (a -> b)而不是a -> m b公共monadic绑定运算符.在有效的环境中,您可以将此视为<*>在不检查中间结果的情况下提供序列效果的方法,而>>=为您提供更多的功能(注意:Applicative Functor和Monad的功能之间的本质区别是一个功能join :: m (m a) -> m a.你认为如何获得>>=与<*>和join?).但是,Applicatives是一个更通用的界面,这意味着您可以在更多情况下使用它们,并且在分析/优化时它们有时可以具有良好的属性.似乎有一个很好的概述Applicatives vs Monads,当你可能想在这里使用Applicatives时.