镜头/棱镜有错误处理

Jam*_*ies 18 haskell scala lenses haskell-lens monocle-scala

假设我有一对转换函数

string2int :: String -> Maybe Int
int2string :: Int -> String
Run Code Online (Sandbox Code Playgroud)

我可以使用Optics轻松地代表这些.

stringIntPrism :: Prism String Int

但是,如果我想表示失败原因,我需要将它们作为两个单独的函数保留.

string2int :: String -> Validation [ParseError] Int
int2string :: Int -> String`
Run Code Online (Sandbox Code Playgroud)

对于这个简单的例子Maybe非常好,因为我们总是可以假设失败是解析失败,因此我们实际上不必使用Either或Validation类型对此进行编码.

但是想象一下,除了解析Prism之外,我还想进行一些验证

isOver18 :: Int -> Validation [AgeError] Int
isUnder55 :: Int -> Validation [AgeError] Int
Run Code Online (Sandbox Code Playgroud)

将这些东西组合在一起是理想的,这样我就可以拥有

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

这对于手工构建来说是相当微不足道的,但是它似乎是一个普遍的概念,在镜头/光学领域潜藏着可能存在的东西.是否存在处理此问题的现有抽象?

TL;博士

是否有一种标准的方法来实现部分镜头/棱镜/ iso,可以通过任意仿函数进行参数化,而不是直接绑定到Maybe?.

我上面使用了Haskell表示法,因为它更直接,但我实际上是在Scala中使用Monocle来实现它.但是,对于ekmett的Lens库特定的答案,我会非常满意.

pha*_*dej 5

我最近写了一篇关于索引光学的博客文章 ; 这也探讨了我们如何做硬核光学.

简而言之:Coindexed-optics是可能的,但我们还没有在那里做进一步的研究.特别是,因为如果我们尝试将这种方法转换lens为镜头编码(从Profunctor到VL),它会变得更加毛茸茸(但我认为我们只能使用 7种类型变量).

如果不改变索引光学器件当前编码的方式,我们就无法做到这一点lens.所以现在,您最好使用验证特定的库.

给出一些困难的暗示:当我们试图用Traversals 组成时,我们应该有

-- like `over` but also return an errors for elements not matched
validatedOver :: CoindexedOptic' s a -> (a -> a) -> s -> (ValidationErrors, s)
Run Code Online (Sandbox Code Playgroud)

或者是其他东西?如果我们只能组成Coindexed Prisms,它们的价值就不能证明它们的复杂性; 它们不会"适应"光学框架.