suk*_*mel 3 haskell haskell-lens
假设我有一个包含两个字段的对象:
data Example = Example { _position :: Int
, _storage :: [Int]}
Run Code Online (Sandbox Code Playgroud)
如何构建聚焦于position内部元素的镜头storage?
另外,是否可以将position通过镜头修改的值限制在基于尺寸的范围内storage?
似乎可以以某种方式使用旁边Example,因为它与元组同构,但我无法理解这样做的方法。
我不知道如何表达这个问题,所以我无法找到很多相关信息。
编辑:我误解了这个问题,原始答案在最后。
我不知道有哪个组合器可以满足您的要求,所以我写了一个。
(^>>=) :: Lens' s a -> (a -> Lens' s b) -> Lens' s b
-- Lens' s a -> (a -> (b -> f b) -> s -> f s) -> (b -> f b) -> s -> f s
-- (That previous line disregards a forall and the Functor constraints)
(x ^>>= f) btofb s = f (s ^. x) btofb s
Run Code Online (Sandbox Code Playgroud)
省略类型签名并询问 ghci 应该会给我们最通用的类型签名,所以这里是:
:t (^>>=)
Getting a s a -> (a -> t1 -> s -> t) -> t1 -> s -> t
Run Code Online (Sandbox Code Playgroud)
Getting 的文档:“当您在类型签名中看到这一点时,它表明您可以向函数传递 Lens、Getter、Traversal、Fold、Prism、Iso 或索引变体之一,并且它只会“做正确的事情” ”。
右侧同样通用,允许遍历/棱镜/等等。
请注意,如果指针不是指向其自身,则这只会产生合法的透镜状图像。
现在应用这个组合器 - 您想要的组合是:
position ^>>= \p -> storage . ix p
Run Code Online (Sandbox Code Playgroud)
这是一个遍历,请参阅原始答案。
或者,使用我喜欢的另一个组合器:
let (f .: g) x = f . g x in position ^>>= (storage .: ix)
Run Code Online (Sandbox Code Playgroud)
任何带有一些中缀声明的东西,你甚至可以去掉那些括号。
(这个原始答案假设position :: Int局部阴影定位镜头。)
我们不知道列表在该位置是否有值,因此这不是“Lens”,而是“Traversal”,它代表“遍历任意数量的值”而不是“镜头到一个值”。
storage . ix position :: Traversal' Example Int
Run Code Online (Sandbox Code Playgroud)
(^?) 将返回遍历的第一个值(如果有),因此如果该位置有效,则此项将为您提供 Int,如果无效,则为 Nothing。
(^? storage . ix position) :: Example -> Maybe Int
Run Code Online (Sandbox Code Playgroud)
该部分版本将假设该位置有效,如果无效则崩溃。
(^?! storage . ix position) :: Example -> Int
Run Code Online (Sandbox Code Playgroud)
(%~) 将右侧的函数应用于左侧遍历的所有内容,不仅适用于镜头,而且适用于所有遍历。(每个镜头都是巧妙的 ekmett 技巧的遍历,并且可以插入遍历可以到达的任何地方。)
storage . ix position %~ (+1) :: Example -> Example
Run Code Online (Sandbox Code Playgroud)
如果您绝对必须使用镜头,那么如果您尝试将它们应用在无效位置,则这些部分术语中的任何一个都会崩溃。
singular $ storage . ix position :: Lens' Example Int
storage . singular (ix position) :: Lens' Example Int
Run Code Online (Sandbox Code Playgroud)
PS:你的记录看起来你可能需要拉链:如果你只增量地向前/向后移动,如果你跟踪当前位置左侧的值列表,你会做更少的臭(!!)事情,当前位置的值以及当前位置右侧的值列表,而不是所有值和您在其中的位置的列表。想要获得更多镜头乐趣,请查看Control.Lens.Zipper,但它们经过了优化,可以优雅地嵌套多个级别的拉链。
| 归档时间: |
|
| 查看次数: |
413 次 |
| 最近记录: |