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

Haskell中该单子式字符串分割函数的工作原理是什么?

拆解按空白分割字符串的Haskell无点式函数

先给这个函数补全类型签名,方便理解:

f :: String -> [String]
f = takeWhile (not . null) . evalState (repeatM $ modify (drop 1) >> State (break (== ' '))) . (' ' :)
  where repeatM = sequence . repeat

下面一步步拆解执行逻辑:

1. 整体流程概述

函数是三个操作的管道组合:

  • 先给输入字符串前置一个空格
  • 用State monad无限执行分割动作,收集每次的结果
  • 过滤掉结果列表中的空字符串,得到最终的分割结果

2. 逐个部分解析

前置空格:(' ' :)

作用是统一处理输入的开头——比如输入"hello world"会变成" hello world"。这一步是为了让后续的分割逻辑无需区分"第一个单词没有前置空格"的特殊情况,让所有单词都能被相同的逻辑处理。

核心State动作:repeatM $ modify (drop 1) >> State (break (== ' '))

先看辅助定义repeatM = sequence . repeat:

  • repeat x会生成一个无限重复x的列表
  • sequence能把列表里的多个State动作串起来,变成一个返回"动作结果列表"的State动作
  • 所以repeatM action就是无限重复执行同一个State动作,收集每次的返回值,得到一个无限列表

再看被重复执行的action:modify (drop 1) >> State (break (== ' ')),这是两个State动作的绑定:

  1. modify (drop 1):修改当前的State状态(也就是当前剩余的字符串),把它去掉第一个字符。比如当前状态是" hello world",执行后变成"hello world"。
  2. >>:忽略前一个动作的返回值(modify返回()),执行后一个动作。
  3. State (break (== ' ')):
    • break (== ' ')是Haskell标准函数,作用是把字符串拆成两部分:从开头到第一个空格(不含空格)的前缀,以及包含空格的后缀。比如"hello world"会被拆成("hello", " world"),没有空格的字符串"world"会被拆成("world", "")。
    • State构造函数把String -> (String, String)这样的函数包装成State动作:执行这个动作时,会拿当前的状态字符串做拆分,返回拆分出的前缀(也就是当前的单词),同时把状态更新为拆分出的后缀。

运行State动作:evalState

evalState stateAction initialState的作用是:用initialState作为初始状态,运行stateAction,最终返回动作的结果(忽略最终的状态)。这里的初始状态就是前面加了空格的输入字符串。

运行后会得到一个无限列表:比如输入" hello world",执行过程会生成["hello", "world", "", "", ...]——当状态变成空串后,后续每次执行都会返回空串。

过滤空串:takeWhile (not . null)

从无限列表中依次取元素,直到遇到空串为止,最终得到非空的单词列表,也就是我们要的分割结果。


3. 用例子完整走一遍流程

以输入"hello world"为例:

  1. 前置空格后得到初始状态:s0 = " hello world"
  2. 第一次执行action:
    • modify (drop 1):状态变为s1 = "hello world"
    • State (break ' '):拆分s1得到("hello", " world"),返回"hello",状态更新为s2 = " world"
    • 列表第一个元素:"hello"
  3. 第二次执行action:
    • modify (drop 1):状态变为s3 = "world"
    • State (break ' '):拆分s3得到("world", ""),返回"world",状态更新为s4 = ""
    • 列表第二个元素:"world"
  4. 第三次执行action:
    • modify (drop 1):空串执行drop 1还是空串,状态s5 = ""
    • State (break ' '):拆分空串得到("", ""),返回""
    • 列表第三个元素:""
  5. takeWhile (not . null)取前两个元素,最终结果:["hello", "world"]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 06:37:08