如何在Haskell中获得深层函子的句柄?

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)

嵌套fmaps有哪些好方法?通常它不像这里那么清楚,我最终添加fmaps直到代码类型检查.简单的代码最终成为一堆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))

其他人是否在大型代码库中遇到此问题?这甚至是个问题吗?你如何解决?

tre*_*ook 1

让我来打破这个人们似乎羞于回答的有趣问题。这个问题可能更多地归结为风格问题,因此缺乏答案。

我的方法如下:

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.

希望这可以帮助。