Haskell解析器开发中Applicative操作符<*与*>的使用疑问
简化Haskell解析器的返回值处理
你发现的这个简化技巧真的太赞了!在Parsec这类解析器组合子库中,<*和*>就是专门用来解决这类“只关心解析成功、不需要保留返回值”的场景,完美替代了原来用fmap写一堆占位符的冗余写法。
先拆解下你给出的两个版本:
原来的写法:
sumParser = fmap (\_ a _ b _ -> a + b) ws <*> val <*> plus <*> val <*> eof这里你不得不手动用
_忽略掉ws、plus、eof的返回值,只留两个val的结果做加法,占位符一多,代码不仅啰嗦,可读性也差了不少。简化后的写法:
sumParser = fmap (+) ws *> val <* plus *> val <* eof这两个操作符的作用可以直白理解为:
*>:先跑左边的解析器,把它的结果丢了,只保留右边解析器的输出<*:先跑左边的解析器,留住它的结果,把右边解析器的输出丢了
一步步拆解这个简化版的逻辑:
ws *> val:先解析空白符(结果直接丢),拿到第一个val的值<* plus:攥着第一个val的值,解析加号(结果丢)*> val:丢加号的结果,拿到第二个val的值<* eof:攥着两个val通过fmap (+)组合出来的加法结果,解析结束符(结果丢)
最终效果和原代码完全一致,但代码简洁太多,逻辑也更一目了然。
其实这俩操作符就是Applicative接口的常用工具,本质上是把你手动写的占位符lambda封装成了通用操作:
(*>)等价于(\_ y -> y) <$> a <*> b<*等价于(\x _ -> x) <$> a <*> b
后续你处理更复杂的解析场景时,比如连续跳过多个无关的解析步骤,或者组合多个需要保留的结果,这些操作符会帮你省超多重复代码。
内容的提问来源于stack exchange,提问作者Michael Browning
相关产品推荐
相关产品推荐

