在功能光学中,行为良好的棱镜(我相信在斯卡拉称为局部透镜)应该具有'subpart -> 'parent -> 'parent
类型的设定函数,如果该棱镜“成功”并且在结构上与给定的'parent
参数兼容,则它返回修改了适当子部分以提供'parent
值的给定的'subpart
。如果棱镜“发生故障”并且在结构上与'parent
参数不兼容,则它将返回未经修改的'parent
。
我想知道为什么棱镜不返回'parent option
(Haskellers的Maybe
)来表示set函数的通过/失败性质?程序员不应该从返回类型中判断出该集合是否“成功”吗?
我知道功能光学领域已经进行了很多研究和思考,因此我敢肯定,肯定有一个我似乎找不到的明确答案。
(我来自F#背景,因此对于Haskell或Scala程序员使用的语法有点不透明,我深表歉意。)
最佳答案
要回答“为什么”-镜头等都是严格地归类于类别理论的,所以这实际上是很明确的-您所描述的行为只是从数学中删除的,不是任何人为任何目的定义的东西,而是很远的地方更一般的想法。
好吧,那真的不令人满意。
不确定其他语言的类型系统是否足够强大来表达这一点,但是原则上在Haskell中,棱镜是遍历的一种特殊情况。
遍历是一种“访问”某些“容器”中所有“元素”出现的方式。经典的例子是
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
这通常像
Prelude> mapM print [1..4]
1
2
3
4
[(),(),(),()]
这里的重点是:对 Action /副作用进行排序,然后将结果收集到一个与我们开始时的结构相同的容器中。
棱镜的特殊之处在于,容器被限制为只能包含一个或零个元素†(而一般遍历可以遍历任何数量的元素)。但是
set
运算符对此一无所知,因为它严格来说更通用。令人高兴的是,因此您可以在镜头,棱镜或mapM
上使用它,并始终获得明智的行为。但这不是“只将一次插入结构,否则告诉我是否失败”的行为。并不是说这不是一个明智的操作,而是这不是镜头库所称的“设置”。您可以通过显式匹配并重新构建来实现:
set₁ :: Prism s a -> a -> s -> Maybe s
set₁ p x = case matching p x of
Left _ -> Nothing
Right a -> Just $ a ^. re p
†更精确地:用棱镜将箱子分开:一个容器可能包含一个元素,除此之外没有别的东西,或者它可能没有元素,但可能不相关。
关于scala - 为什么棱镜设置函数不返回Option/也许,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46384203/