Haskell中实现带终止条件的生成器的惯用写法是什么?
你所使用的takeWhileInclusive方案完全是符合Haskell惯用写法的实现。
两种主流的常规实现方式
- 第一种就是你采用的组合子拼接方案:
基于标准库的iterate生成无限序列,再用takeWhileInclusive截断序列,这种写法逻辑和需求语义完全对齐,没有额外的冗余逻辑,可读性极强,不需要引入额外的类型包装,是处理这类场景的首选。
你提到的添加哨兵值再用takeWhile过滤的写法确实不够自然,会额外引入包装、解包的逻辑开销,也会让代码的语义变得模糊,除非你本身需要在迭代过程中传递异常/终止信号,否则完全没必要采用这种写法。 - 第二种是直接封装递归函数实现:
如果你不想额外定义通用的takeWhileInclusive函数,也可以直接封装一个专用于该场景的迭代函数:
调用时直接写-- 语义:迭代生成包含x0、直到命中done条件的所有元素 iterateUntil :: (a -> Bool) -> (a -> a) -> a -> [a] iterateUntil done step x | done x = [x] | otherwise = x : iterateUntil done step (step x)iterateUntil done step x0即可,不需要拼接多个组合子,同样是非常符合Haskell风格的写法。
针对实际业务场景的补充
你在解决盛最多水的容器问题时的写法完全合理,对于没有天然越界判断、只有自定义终止条件的场景,上述两种方案都可以直接复用,不需要做额外的适配。如果是项目中多处需要这类逻辑,推荐封装通用的takeWhileInclusive函数;如果是单次使用的逻辑,直接写递归或者直接用你现有的写法都没有问题。
内容的提问来源于stack exchange,提问作者Eric Auld
相关产品推荐
相关产品推荐

