如何处理 Haskell 中的深堆栈仿函数?

How do I get a handle on deep stacks of functors in Haskell?

时不时地,我发现自己映射到一大堆函子上,例如一些可选值集合的解析器:

-- 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

嵌套 fmap 有哪些好的方法?通常它不像这里那么清楚,我最终会添加 fmaps 直到代码类型检查。简单的代码最终变成一堆乱七八糟的fmap样板,我真正想表达的是"lift this function to the appropriate depth and apply it to the contained type".

一些想法,none 目前我觉得特别满意:

其他人 运行 在大型代码库中遇到过这个问题吗?这甚至是一个问题吗?你是怎么处理的?

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

我的方法如下:

parseClassifiedRectangle :: Parser (Map (Int, Int) (Maybe Class))
parseClassifiedRectangle = doClassify <$> parseRectangle
  where
    doClassify = Map.map (fmap classify)

我尝试将 <$> 用于顶层函子,而将 fmap 用于内部函子;尽管这在实践中并不总是很有效。

我使用了本地命名绑定。但是,即使将 doClassify 保留为 f,它有时也有助于阐明所发生情况的高级视图:"on the parsed value we are doing a thing, see below for what thing does." 我不知道进行绑定的效率问题是什么。

我还使用了 fmap 的特定实例作为 Map 实例。这有助于我在堆栈中定位并为最终 fmap 提供路标。

希望对您有所帮助。