imz*_*hev 11 haskell records function-composition higher-order-functions lenses
我一直在阅读一个wreq教程:
镜头提供了一种聚焦于Haskell值的一部分的方法.例如,该
Response类型具有responseStatus镜头,其关注于服务器返回的状态信息.Run Code Online (Sandbox Code Playgroud)ghci> r ^. responseStatus Status {statusCode = 200, statusMessage = "OK"}在
^.操作者需要一个值作为第一个参数,一个透镜作为其第二个,并返回聚焦值的该部分上由透镜.我们使用功能组合构成镜头,这使我们可以轻松地专注于深层嵌套结构的一部分.
Run Code Online (Sandbox Code Playgroud)ghci> r ^. responseStatus . statusCode 200
我无法想出如何使用这个参数顺序完成的函数组合可以按顺序处理嵌套结构.
看:r ^. responseStatus . statusCode可能是r ^. (responseStatus . statusCode)或者(r ^. responseStatus) . statusCode.
在第一个中我们构造了一个函数,它首先处理statusCode(从记录中获取它Status? - 因为我可以从显示的值中推导出来Status {statusCode = 200, statusMessage = "OK"}),然后将它传递给responseStatus必须处理响应状态的函数.所以,反过来说:实际上,状态代码是响应状态的一部分.
第二读对我来说也没有意义,因为它也首先处理状态代码.
And*_*ács 13
正确的阅读r ^. responseStatus . statusCode是r ^. (responseStatus . statusCode).这很自然,因为函数组合在应用于两个参数时返回一个函数,因此(r ^. responseStatus) . statusCode必须返回一个函数,而不是可以打印出来的任何值.
这仍然留下了为什么镜头构成"错误"顺序的问题.由于镜头的实现有点神奇,让我们看一个更简单的例子.
first 是一个映射在一对的第一个元素上的函数:
first :: (a -> b) -> (a, c) -> (b, c)
first f (a, b) = (f a, b)
Run Code Online (Sandbox Code Playgroud)
怎么map . first办?first接受一个作用于第一个元素的函数,并返回一个作用于一对的函数,如果我们用这种方式括起这个类型就更明显了:
first :: (a -> b) -> ((a, c) -> (b, c))
Run Code Online (Sandbox Code Playgroud)
还记得以下类型map:
map :: (a -> b) -> ([a] -> [b])
Run Code Online (Sandbox Code Playgroud)
map获取作用于元素的函数并返回作用于列表的函数.现在,f . g首先应用g然后将结果输入到f.因此,map . first将一个函数作用于某个元素类型,将其转换为作用于对的函数,然后将其转换为作用于对列表的函数.
(map . first) :: (a -> b) -> [(a, c)] -> [(b, c)]
Run Code Online (Sandbox Code Playgroud)
first并且map两者都将作用于结构的一部分的函数转换为作用于整个结构的函数.在map . first,整个结构是什么first成为焦点map.
(map . first) (+10) [(0, 2), (3, 4)] == [(10, 2), (13, 4)]
Run Code Online (Sandbox Code Playgroud)
现在来看看镜片的类型:
type Lens = forall f. Functor f => (a -> f b) -> (s -> f t)
Run Code Online (Sandbox Code Playgroud)
暂时忽略这些Functor位.如果我们稍微斜视,这类似于map和first.它的发生使得镜头还将作用于结构部件的功能转换为作用于整个结构的功能.在上面的签名中s表示整个结构并a表示它的一部分.由于我们的输入功能可以改变的类型a,以b(由所示a -> f b),我们还需要t参数,大致意思是"类型s之后,我们改变a到b里面".
statusCode是一个镜头,它将作用于某个函数的函数转换为一个函数Int,该函数作用于Status:
statusCode :: Functor f => (Int -> f Int) -> (Status -> f Status)
Run Code Online (Sandbox Code Playgroud)
responseStatus将作用于a Status的函数转换为作用于a 的函数Response:
responseStatus :: Functor f => (Status -> f Status) -> (Response -> f Response)
Run Code Online (Sandbox Code Playgroud)
类型responseStatus . statusCode与我们看到的模式相同map . first:
responseStatus . statusCode :: Functor f => (Int -> f Int) -> (Response -> f Response)
Run Code Online (Sandbox Code Playgroud)
还有待观察究竟是如何^.运作的.它与镜头的核心机制和魔力密切相关; 我不会在这里重申,因为有很多关于它的着作.对于介绍我建议看这个和这个,你也可以看这个优秀的视频.
| 归档时间: |
|
| 查看次数: |
447 次 |
| 最近记录: |