Control.Lens.Tuple定义用于访问元组元素的透镜。例如
class Field3 s t a b | s -> a, t -> b, s b -> t, t a -> s where
-- | Access the 3rd field of a tuple.
_3 :: Lens s t a b
-- >>> (1,2,3)^._3
-- 3
--
-- >>> _3 .~ "hello" $ (1,2,3)
-- (1,2,"hello")
setter _3 .~
返回一个元组,其中第三个元素已更改,在此示例中为其他类型。
对于类Field3
,为具有三个或更多元素的元组定义了实例。不适合成对/两人,因为吸气剂会得到什么?
但是如果setter可以更改第n个元素的类型,为什么它不能将类型更改为其他元组呢?
-- >>> _3 .~ "hello" $ (1,2)
-- (1,2,"hello")
也就是说,设置器_3 .~
通过扩展两个整数来设置第三个元素。
instance Field3 (a,b) (a,b,c') Dummy c' where
_3 k ~(a,b) = k undefined <&> \c' -> (a,b,c')
其中Dummy
和undefined
是占位符的类型和值,用于传入的二元组中不存在的第三个元素。
扩展到Arity 3之后,镜头_3
照常工作;镜头_1, _2
始终遵守镜头定律。
Q1。这对二传手有用吗?
(当然,它不会用于更新程序/ over
)
Q2。如果是这样,有什么办法可以使它错误地尝试view
处理不存在的第三个元素?
Q3。如果设置器不起作用,是否可以使用extend
运算符来达到效果? (大概使用其他函子。)
也许实例可能是这个
instance Field3 (a,b) (a,b,c') (a,b) c' where
_3 k ~(a,b) = k (a,b) <&> \c' -> (a,b,c')
view
将返回一个奇怪的输入结果,而over
可能会从前两个元素中构建第三个元素。
答案 0 :(得分:1)
在van Laarhoven透镜配方中,光学器件只是一种高阶函数,对较小的结构起作用,而对较大的结构起作用。可以组合这些函数,然后将其与lens
软件包中提供的糖一起使用,以使调用它们变得无聊。但是也可以调用它们。
假设您有这个:
bigStructure :: (Int, (Int, (Int, Int)))
bigStructure = (0, (1, (2, 3)))
您想将10
附加到最里面的一对。这是对那对子的动作,这是大结构中较小的一部分。
mk3ple :: c -> (a, b) -> (a, b, c)
mk3ple = flip $ uncurry (,,)
因此_2 . _2
是聚焦于最里面的那个对的镜头-换句话说,它是一个函数,它对最里面的那个对采取行动,对大结构采取行动。因此,让我们...将mk3ple
传递给它(over
这样做;它只是为我们处理了Identity
个繁琐的工作):
over (_2 . _2) (mk3ple 10) bigStructure
这里有一个Setter
的设置器(概念性,即不是文字bigStructure
),它使用需要聚焦在元组上的任何透镜。
当然,如果您希望元组附加器成为具有吸气剂和所有功能的实际镜头,那么您当然也可以这样做!只需将单元视为每个元组的一部分,然后编写:
mk3ple' :: Lens (a, b) (a, b, c) () c
mk3ple' = lens (const ()) (uncurry (,,))
set (_2 . _2 . mk3ple') 10 bigStructure