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

为何Prism的_Show在列表中不生效?如何解释空列表结果?

Haskell中_Show棱镜的行为问题及解决方法

问题重现

以下是三段Haskell代码执行示例:

[Just 1, Just 2, Nothing, Just 3]^..folded._Just
[1,2,3]

"1"^?_Show::Maybe Int
Just 1

["1", "2", "x"]^..folded._Show :: [Maybe Int]
[]

其中_Just和_Show均为棱镜,类型如下:

:t _Just
_Just :: Prism (Maybe a) (Maybe b) a b
:t _Show
_Show :: (Read a, Show a) => Prism' String a

第三个示例返回空列表,不符合预期。需要解释该结果,并找到无需使用to辅助函数、仅用Lens/Prism得到[Just 1, Just 2]的方法。

结果原因解释

  1. 棱镜的折叠逻辑:^..(即toListOf)配合棱镜使用时,仅会收集匹配成功的元素值,匹配失败的元素会被直接忽略,不会产生任何输出。_Show作为Prism' String a,其匹配逻辑是尝试将输入字符串通过read解析为目标类型,成功则返回解析值,失败则匹配失败。
  2. 类型标注冲突:第三个示例中你标注了结果类型为[Maybe Int],但folded._Show实际产生的是[Int](仅包含解析成功的1和2)。由于[Int]与[Maybe Int]类型不匹配,GHC无法完成转换,最终返回空列表。

解决方法

要得到[Just 1, Just 2]的结果,需要对每个元素单独执行_Show的匹配操作,再收集成功的Maybe值,无需使用to辅助函数:

方法1:结合^?与filter

import Control.Lens
import Data.Maybe (isJust)

filter isJust $ map (^?_Show) ["1", "2", "x"] :: [Maybe Int]
  • ^?_Show等价于preview _Show,对单个字符串执行匹配,返回Maybe Int;
  • map遍历整个列表,得到[Just 1, Just 2, Nothing];
  • filter isJust过滤掉Nothing,最终得到[Just 1, Just 2]。

方法2:结合preview与mapMaybe

import Control.Lens.Prism (preview)
import Data.Maybe (mapMaybe, Just(..))

map Just $ mapMaybe (preview _Show) ["1", "2", "x"] :: [Maybe Int]
  • mapMaybe (preview _Show)先过滤出解析成功的Int值,得到[1,2];
  • map Just将每个Int包裹为Just,得到目标结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 19:29:52