You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell自定义Parser中<*、*>操作符工作原理与字符串传递逻辑疑问

剩余字符串传递逻辑解析

你观察到的字符串传递逻辑,完全由你已经实现的Applicative的<*>方法定义,*>和<*>都是Applicative类型类提供的默认派生方法,没有额外的隐藏逻辑。

前置说明:parseChar的参考实现

为了方便走流程,我们先明确示例中parseChar的常见实现:

parseChar :: Char -> Parser Char
parseChar c = Parser $ \s -> case s of
  (x:xs) | x == c -> Just (c, xs)
  _ -> Nothing

第一步:明确*>和<*的默认实现

这两个操作符不需要你手动实现,是基于你已经写好的fmap和<*>派生的:

-- 丢弃左边解析值,保留右边解析值
(*>) :: Applicative f => f a -> f b -> f b
p1 *> p2 = fmap (\_ b -> b) p1 <*> p2

-- 保留左边解析值,丢弃右边解析值
(<*) :: Applicative f => f a -> f b -> f a
p1 <* p2 = fmap (\a _ -> a) p1 <*> p2

第二步:结合你实现的<*>逻辑看字符串传递

你自己写的<*>实例逻辑非常明确:

  1. 先拿输入字符串运行左侧的解析器,得到解析结果(函数值)和剩余字符串str1
  2. 直接把str1作为输入运行右侧的解析器,得到解析结果(参数值)和剩余字符串str2
  3. 把函数应用到参数上,最终返回(应用后的结果, str2)

不管是*>还是<*,都只是修改了<*>最终返回的结果值,完全不会改变「从左到右执行、前一个解析器的剩余输出是后一个解析器的输入」的执行流程。

第三步:走一遍你的示例完整流程

你的示例runParser (parseChar 'x' *> parseChar 'a' <* parseChar 'x') "xax"的执行顺序是左结合,等价于runParser ((parseChar 'x' *> parseChar 'a') <* parseChar 'x') "xax":

  1. 先执行parseChar 'x' *> parseChar 'a':
    • 输入字符串是"xax",先跑parseChar 'x'匹配到x,返回剩余字符串"ax",同时按照*>的定义把解析值'x'替换为函数\_ b -> b
    • 把"ax"传给parseChar 'a'执行,匹配到a,返回剩余字符串"x"
    • 函数应用得到结果'a',这一步执行完成后得到的中间结果是('a', "x")
  2. 再执行<* parseChar 'x':
    • 把上一步得到的剩余字符串"x"作为输入传给parseChar 'x'执行,匹配到x,返回剩余字符串""
    • 按照<*的定义保留左边的'a'作为最终结果
  3. 最终返回Just ('a', ""),和你的示例结果一致。

核心总结

  • 解析器永远从左到右顺序执行,剩余字符串按执行顺序依次向后传递,这个逻辑是你写的<*>实例已经定义好的
  • 箭头指向仅用于决定最终保留哪一侧的解析值,和字符串传递、执行顺序没有任何关系

内容的提问来源于stack exchange,提问作者apocalyptica1972

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 16:39:03