镜头/棱镜与错误处理

20

假设我有一对转换函数

string2int :: String -> Maybe Int
int2string :: Int -> String

使用Optics,我可以很容易地表示这些。

stringIntPrism :: Prism String Int

然而,如果我想要表示失败原因,我需要将它们保留为两个单独的函数。

string2int :: String -> Validation [ParseError] Int
int2string :: Int -> String`

对于这个简单的例子,Maybe是完全可以的,因为我们总是可以假定失败是一个解析失败,因此我们实际上不必使用 Either 或 Validation 类型来编码它。

然而,想象一下,在我的解析 Prism 之外,我还想执行一些验证。

isOver18 :: Int -> Validation [AgeError] Int
isUnder55 :: Int -> Validation [AgeError] Int

希望能够将这些东西组合在一起,比如我可以这样做:

ageField = isUnder55 . isOver18 . string2Int :: ValidationPrism [e] String Int

手动构建这个函数很容易,但似乎这是一个常见的概念,也许在Lenses / Optics领域中已经存在处理这个问题的抽象。是否存在处理这个问题的现有抽象?

总之:

是否有标准方法实现可以针对任意Functor参数化部分镜头/棱镜/等距变换,而不是直接绑定在Maybe上?

我在上面使用了Haskell符号,因为它更简单明了,但实际上我正在使用Scala中的Monocle来实现这个。然而,如果回答针对例如ekmett的Lens库是非常具体的,我也会非常高兴。


8
我记得很久以前Reddit上有一个类似的讨论。 Edward Kmett在其中提到了“共同索引棱镜”的概念,它可以在保持与正常透镜组合的同时报告错误信息。显然,由于类型推断问题,它们很难被整合到透镜框架中,因此没有被实现。 - danidiaz
我认为“遍历”这个概念在这里是合适的。 - 9b5b
1个回答

6
我最近写了一篇关于索引光学的博客文章(链接),其中探讨了如何使用共指光学。
简而言之:共指光学是可行的,但我们还需要进一步研究。特别是,如果我们试图将该方法转化为lens编码的镜头(从Profunctor到VL),那么它会变得更加复杂(但我认为我们仅需使用7个类型变量就可以解决)。
而且,我们真的不能在不改变当前在lens中编码索引光学的方式的情况下实现这一点。因此,现在最好使用专门的验证库。
为了给出困难的提示:当我们尝试与Traversal组合时,我们应该有
-- like `over` but also return an errors for elements not matched
validatedOver :: CoindexedOptic' s a -> (a -> a) -> s -> (ValidationErrors, s)

或者其他的东西?如果我们只能组合共索引棱镜,它们的价值将无法证明它们的复杂性;它们将无法“适应”光学框架。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接