Data.List 插入单子

Data.List intercalate for monads

我正在使用 ReadP 模块编写一个小型解析器。我有这个表达:

cmdExpr = string "create" <|> string "add" <|> string "another alias" <|> ...

我想抽象掉 <|> 操作,但我不知道该怎么做。类似于 intercalate:

getExpr cmds = intercalateM (<|>) $ map string cmds
cmdExpr = getExpr ["create", "add", "another alias", ...]

有什么想法吗?

您可以使用 choice:

Prelude Text.ParserCombinators.ReadP> cmds = ["create", "add", "another alias"]
Prelude Text.ParserCombinators.ReadP> :t choice $ map string cmds
choice $ map string cmds :: ReadP String

你需要的是折叠。

<|> 不是列表元素,它是一个带有两个参数的关联函数。

你需要做这样的事情:

getExpr cmds = foldr1 (<|>) $ map string cmds

请注意,使用 foldr1 是一种快速而肮脏的修复方法:如果给定一个空列表,它将抛出异常。稳健的方法是将 foldr 与某种空解析器一起用作基本情况。

这是 asumMap in Relude 的完美用例:

getExpr cmds = asumMap string cmds
cmdExpr = getExpr ["create", "add", "another alias", ...]

如果你不是用Relude而是用其他第三方库,那么还有其他相同的功能,比如altMap in Util:

import Util (altMap)
getExpr cmds = altMap string cmds
cmdExpr = getExpr ["create", "add", "another alias", ...]

如果你想坚持使用Base,那么你可以分别使用asummap:

import Data.Foldable (asum)
getExpr cmds = asum $ map string cmds
cmdExpr = getExpr ["create", "add", "another alias", ...]