为何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]的方法。
结果原因解释
- 棱镜的折叠逻辑:
^..(即toListOf)配合棱镜使用时,仅会收集匹配成功的元素值,匹配失败的元素会被直接忽略,不会产生任何输出。_Show作为Prism' String a,其匹配逻辑是尝试将输入字符串通过read解析为目标类型,成功则返回解析值,失败则匹配失败。 - 类型标注冲突:第三个示例中你标注了结果类型为
[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
相关产品推荐
相关产品推荐

