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")
设置器_3 .~
返回一个元组,其中第三个元素已更改,例如在此示例中更改为不同的类型。
对于类Field3
,已经针对具有三个或更多元素的元组定义了实例。没有定义用于成对/双元组的实例,因为getter将得到什么呢?
但是,如果setter可以更改第n个元素的类型,为什么它不能将类型更改为不同元组度数的类型呢?
-- >>> _3 .~ "hello" $ (1,2)
-- (1,2,"hello")
也就是说,使用 setter
_3 .~
可以通过扩展一个二元组来设置第三个元素。instance Field3 (a,b) (a,b,c') Dummy c' where
_3 k ~(a,b) = k undefined <&> \c' -> (a,b,c')
Dummy
和undefined
是一些占位符类型和值,用于不存在的二元组的第三个元素。
扩展到3元后,镜头_3
像往常一样工作;同时镜头_1, _2
在整个过程中都遵守着镜头法则。
问题1:这对于Setter来说有效吗?
(当然不适用于Updater/over
)
问题2:如果是,有没有某种方法可以使其类型错误而尝试view
非存在的第三个元素?
问题3:如果Setter行不通,是否有一种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
方法可以根据前两个元素来构建第三个元素。
_3 .~ "hello" $ (1,2)
被接受并产生了我想要的结果。但是该实例没有被接受:与正确实例不一致,对于 FunDept a -> s
-- 这是非常正确的。我只是在类上抑制了那个 FunDep。 - AntC(a, b) -> c -> (a, b, c)
,那么镜片基础设施的其余部分提供了什么是_3' = uncurry (,,)
没提供的?某种通用性吗? - user11228628_3'
就不是这样的。我看不到任何函子。 - AntCFunctor
上操作;它的Functor
是Identity
。如果你有一个van Laarhoven镜头forall f. Functor f => ((a, b) -> f (a, b, c)) -> s -> f t
,你应该能够将其与c -> (a, b) -> Identity (a, b, c)
组合,以获得你想要的更大结构的样式的setter。这就是van Laarhoven镜头的美妙之处;你可以用普通的组合做很多事情。 - user11228628set _3 "hello" (1, 2)
可以得到(1,2,"hello")
,且_3
的类型有一个Functor的约束条件。使用你的定义set _3' "hello" (1,2)
是无效的,而_3'
的类型并没有提到Functor。set
会引入Identity
Functor。 - AntC