具有相互依赖(同时)更新的镜头
Lenses with interdependent (simultaneous) updates
假设我有:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
import Control.Lens
data T a b = T { _foo :: a
, _bar :: a -> b
}
makeLenses ''T
a
出现在 foo
和 bar
中,因此更新必须是 "simulatenous"。没有镜头也是可能的:
eg1 :: T a (b -> c) -> b -> T (a, b) c
eg1 (T foo bar) b = T (foo, b) (uncurry bar)
但是我怎样才能用镜头做到这一点呢?以下不适用于发生检查:
eg :: T a (b -> c) -> b -> T (a, b) c
eg t b = t & foo %~ (, b) & bar %~ uncurry
您无法使用 T
自动生成的镜头执行此操作。如果你想稍微扩展一下,你可以先定义
data T' a b c = T' { _foo' :: c, _bar' :: a -> b}
tt :: Iso (T a b) (T a' b') (T' a b a) (T' a' b' a')
tt = dimap (\(T x g) -> T' x g) (fmap (\(T' x g) -> T x g))
然后你可以(自动)为T'
构建类型改变的镜头,并使用tt
使用它们通过同构修改T a b
类型的值。
例如,稍微重新排列参数,您可以这样写
eg :: b -> T a (b -> c) -> T (a, b) c
eg b = over tt $ (foo' %~ (,b)) . (bar' %~ uncurry)
另一种方法可能会更好,如果你不需要对 T
太过纠结的话,那就是将它定义为 newtype
围绕 T'
:
newtype T a b = T { getT :: T' a b a }
然后您可以跳过 Iso
并编写内容。以同样的方式重新排列参数,
eg' :: b -> T a (b -> c) -> T (a, b) c
eg' b = T . (foo' %~ (,b)) . (bar' %~ uncurry) . getT
假设我有:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
import Control.Lens
data T a b = T { _foo :: a
, _bar :: a -> b
}
makeLenses ''T
a
出现在 foo
和 bar
中,因此更新必须是 "simulatenous"。没有镜头也是可能的:
eg1 :: T a (b -> c) -> b -> T (a, b) c
eg1 (T foo bar) b = T (foo, b) (uncurry bar)
但是我怎样才能用镜头做到这一点呢?以下不适用于发生检查:
eg :: T a (b -> c) -> b -> T (a, b) c
eg t b = t & foo %~ (, b) & bar %~ uncurry
您无法使用 T
自动生成的镜头执行此操作。如果你想稍微扩展一下,你可以先定义
data T' a b c = T' { _foo' :: c, _bar' :: a -> b}
tt :: Iso (T a b) (T a' b') (T' a b a) (T' a' b' a')
tt = dimap (\(T x g) -> T' x g) (fmap (\(T' x g) -> T x g))
然后你可以(自动)为T'
构建类型改变的镜头,并使用tt
使用它们通过同构修改T a b
类型的值。
例如,稍微重新排列参数,您可以这样写
eg :: b -> T a (b -> c) -> T (a, b) c
eg b = over tt $ (foo' %~ (,b)) . (bar' %~ uncurry)
另一种方法可能会更好,如果你不需要对 T
太过纠结的话,那就是将它定义为 newtype
围绕 T'
:
newtype T a b = T { getT :: T' a b a }
然后您可以跳过 Iso
并编写内容。以同样的方式重新排列参数,
eg' :: b -> T a (b -> c) -> T (a, b) c
eg' b = T . (foo' %~ (,b)) . (bar' %~ uncurry) . getT