如何使用 lens 实现 unsafePartsOf
How to implement unsafePartsOf using lens
我正在尝试使用专用签名实现 unsafePartsOf
的简单版本:
unsafePartsOf :: Traversal s t a b -> Lens s t [a] [b]
在尝试了解它的工作原理后,我想到了这个 (repl)。
myUnsafePartsOf :: Traversal s t a b -> Lens s t [a] [b]
myUnsafePartsOf traverse = lens getter setter
where
-- getter :: s -> [a]
getter s = s ^.. traverse
-- setter :: s -> [b] -> t
setter s xs = evalState (s & traverse %%~ assignElem) xs
assignElem _a = state $ \case
[] -> error "list not long enough"
(b : bs) -> (b, bs)
我觉得用lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
来区分getter和setter的定义会更容易理解。
但是,此函数不进行类型检查,因为 ^..
运算符 (toListOf
) 具有 toListOf :: Traversal' s a -> s -> [a]
的(专用)签名,其中原始 s
和 t
(以及 a
和 b
)将统一。
然后我尝试使用以下代码实现更通用的 toListOf
(the same repl) 版本:
toListOf :: Traversal s t a b -> s -> [a]
toListOf traverse s = execState (traverse getElem s) []
where getElem a = modify (a:)
但再次失败,因为使用 modify
需要将 b
与 ()
统一。我知道我无法在 getElem
中创建任意 b
所以这个功能是不可能的。
请注意,实际上可以以类似的方式使用 lens
定义保险箱 partsOf
:
myPartsOf :: Traversal' s a -> Lens' s [a]
myPartsOf t = lens getter setter
where
getter s = s ^.. t
-- setter :: s -> [a] -> s
setter s xs = evalState (s & t %%~ assignElem) xs
assignElem a = state $ \case
[] -> (a, [])
(x : xs) -> (x, xs)
是否可以使用 lens
定义 unsafePartsOf
?如果可以,我该怎么做?
您可以将 getter
定义为:
getter s = s ^.. (\f -> Const . getConst . traverse (Const . getConst . f))
它似乎可以进行类型检查。
我正在尝试使用专用签名实现 unsafePartsOf
的简单版本:
unsafePartsOf :: Traversal s t a b -> Lens s t [a] [b]
在尝试了解它的工作原理后,我想到了这个 (repl)。
myUnsafePartsOf :: Traversal s t a b -> Lens s t [a] [b]
myUnsafePartsOf traverse = lens getter setter
where
-- getter :: s -> [a]
getter s = s ^.. traverse
-- setter :: s -> [b] -> t
setter s xs = evalState (s & traverse %%~ assignElem) xs
assignElem _a = state $ \case
[] -> error "list not long enough"
(b : bs) -> (b, bs)
我觉得用lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
来区分getter和setter的定义会更容易理解。
但是,此函数不进行类型检查,因为 ^..
运算符 (toListOf
) 具有 toListOf :: Traversal' s a -> s -> [a]
的(专用)签名,其中原始 s
和 t
(以及 a
和 b
)将统一。
然后我尝试使用以下代码实现更通用的 toListOf
(the same repl) 版本:
toListOf :: Traversal s t a b -> s -> [a]
toListOf traverse s = execState (traverse getElem s) []
where getElem a = modify (a:)
但再次失败,因为使用 modify
需要将 b
与 ()
统一。我知道我无法在 getElem
中创建任意 b
所以这个功能是不可能的。
请注意,实际上可以以类似的方式使用 lens
定义保险箱 partsOf
:
myPartsOf :: Traversal' s a -> Lens' s [a]
myPartsOf t = lens getter setter
where
getter s = s ^.. t
-- setter :: s -> [a] -> s
setter s xs = evalState (s & t %%~ assignElem) xs
assignElem a = state $ \case
[] -> (a, [])
(x : xs) -> (x, xs)
是否可以使用 lens
定义 unsafePartsOf
?如果可以,我该怎么做?
您可以将 getter
定义为:
getter s = s ^.. (\f -> Const . getConst . traverse (Const . getConst . f))
它似乎可以进行类型检查。