用于元组扩展的镜头?

时间:2019-05-04 09:28:32

标签: haskell lenses

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')

其中Dummyundefined是占位符的类型和值,用于传入的二元组中不存在的第三个元素。

扩展到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可能会从前两个元素中构建第三个元素。

1 个答案:

答案 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