我正在使用ReadP模块编写一个小型解析器。我有这个表情:
cmdExpr = string "create" <|> string "add" <|> string "another alias" <|> ...
我想抽象化<|>
操作,但是我不知道如何操作。类似于intercalate
:
getExpr cmds = intercalateM (<|>) $ map string cmds
cmdExpr = getExpr ["create", "add", "another alias", ...]
有什么想法吗?
答案 0 :(得分:6)
您可以使用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
答案 1 :(得分:4)
您需要的是折叠。
<|>
不是列表元素,它是一个带有两个参数的关联函数。
您需要执行以下操作:
getExpr cmds = foldr1 (<|>) $ map string cmds
请注意,使用foldr1
是一种快速而肮脏的解决方案:如果给定一个空列表,它将引发异常。健壮的方法是将foldr
与某种空解析器一起用作基本情况。
答案 2 :(得分:1)
这是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,那么可以分别使用as David Fletcher mentioned in a comment和asum
和map
:
import Data.Foldable (asum)
getExpr cmds = asum $ map string cmds
cmdExpr = getExpr ["create", "add", "another alias", ...]