使用镜头组成功能

Cli*_*ton 2 haskell lenses haskell-lens

考虑具有以下(伪)签名的"组合"函数:

(a1 -> a2 -> ... -> an -> r) -> 
(s -> ai) -> 
a1 -> a2 -> ... -> ai -> ... an -> r
where i in [1..n]
Run Code Online (Sandbox Code Playgroud)

当然我们不能在Haskell中编写上面的内容,但这是一个具体的例子:

f4change3 :: 
  (a1 -> a2 -> a3 -> a4 -> r) -> 
  (s -> a3) -> 
  a1 -> a2 -> s -> a4 -> r
f4change3 f g x1 x2 x3 x4 = f x1 x2 (g x3) x4
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,narity的每个函数都有一组函数n,因此我们需要的函数数量与arity呈二次方式增长.

我可以写出我需要的那些,但首先,我不想重新发明轮子,所以很高兴知道库是否已经完成了这个.但是,虽然我几乎没有使用镜头,但我已经阅读了一些关于它们的内容,这种问题似乎正好在他们的盟友身上,但我不确定该怎么做.如果可能的话,一些示例代码会很棒.

Dan*_*ner 5

正如评论中所提到的,Conal Elliott的语义编辑器组合器为编写这些函数提供了一个非常漂亮的工具.让我们回顾一下他的两个组合器:

argument :: (a' -> a) -> ((a -> b) -> (a' -> b))
argument = flip (.)

result :: (b -> b') -> ((a -> b) -> (a -> b'))
result = (.)
Run Code Online (Sandbox Code Playgroud)

单词:argument在调用函数之前修改函数的参数,并result在调用函数后修改函数的返回值.(请参阅博客文章本身,以获得进一步的直觉 - 支持这些组合器的解释.)假设我们有一个类似的类型的函数

a1 -> a2 -> a3 -> a4 -> a5 -> b
Run Code Online (Sandbox Code Playgroud)

我们想要改变a5.请注意,我们当然可以将其括起来:

a1 -> (a2 -> (a3 -> (a4 -> (a5 -> b))))
Run Code Online (Sandbox Code Playgroud)

因此,如果我们想要达成a5,我们应该如何进入这个结构?好吧,我们将通过反复进入result,然后作用于argument:该函数的结果类型a2 -> (a3 -> (a4 -> (a5 -> b))),结果是a3 -> (a4 -> (a5 -> b)),其结果是a4 -> (a5 -> b),其结果是a5 -> b,其参数是a5.这直接为我们提供了代码:

arg5 :: (a5' -> a5)
     -> (a1 -> a2 -> a3 -> a4 -> a5  -> b)
     -> (a1 -> a2 -> a3 -> a4 -> a5' -> b)
arg5 = result . result . result . result . argument
Run Code Online (Sandbox Code Playgroud)

希望很清楚如何概括这个来修改其他参数:只是改变你调用的次数result.