rob*_*obx 6 haskell nested functor
偶尔我会发现自己映射到一大堆仿函数,例如一些可选值集合的解析器:
-- parse a rectangular block of characters to a map of
-- coordinate to the character, or Nothing for whitespace
parseRectangle :: Parser (Map (Int, Int) (Maybe Char))
data Class = Letter | Digit | Other
classify :: Char -> Class
parseClassifiedRectangle :: Parser (Map (Int, Int) (Maybe Class))
parseClassifiedRectangle = fmap (fmap (fmap classify)) parseRectangle
Run Code Online (Sandbox Code Playgroud)
嵌套fmap
s有哪些好方法?通常它不像这里那么清楚,我最终添加fmap
s直到代码类型检查.简单的代码最终成为一堆fmap
样板,我真正想要表达的是"将此函数提升到适当的深度并将其应用于所包含的类型".
一些想法,到目前为止我都没有发现特别令人满意的想法:
fmap2 :: (Functor f, Functor g) => (a -> b) -> g (f a) -> g (f b)
和朋友mapMaybeMap :: (a -> b) -> Map k (Maybe a) -> Map k (Maybe b)
newtype
为functor堆栈引入包装器,并创建那些实例Functor
,如newtype MaybeMapParser a = Parser (Map (Int, Int) (Maybe a))
其他人是否在大型代码库中遇到此问题?这甚至是个问题吗?你如何解决?
让我来打破这个人们似乎羞于回答的有趣问题。这个问题可能更多地归结为风格问题,因此缺乏答案。
我的方法如下:
parseClassifiedRectangle :: Parser (Map (Int, Int) (Maybe Class))
parseClassifiedRectangle = doClassify <$> parseRectangle
where
doClassify = Map.map (fmap classify)
Run Code Online (Sandbox Code Playgroud)
我尝试使用<$>
顶级函子,并保存fmap
内部函子;尽管这在实践中并不总是那么有效。
我使用了本地命名绑定。但即使doClassify
留下来,因为f
它有时有助于澄清正在发生的事情的高级视图:“在解析值上我们正在做一件事,请参阅下面的内容来了解它的作用。” 我不知道进行绑定的效率问题是什么。
我还使用了具体实例fmap
我还使用了Map 实例这有助于我在堆栈中确定方向,并为最终的fmap
.
希望这可以帮助。