use*_*650 7 haskell haskell-lens
让我们说:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
import Control.Lens
data T a b = T { _foo :: a
, _bar :: a -> b
}
makeLenses ''T
Run Code Online (Sandbox Code Playgroud)
a出现在两个foo和bar,因此更新必须是"simulatenous",因为它是.没有镜头可以这样做:
eg1 :: T a (b -> c) -> b -> T (a, b) c
eg1 (T foo bar) b = T (foo, b) (uncurry bar)
Run Code Online (Sandbox Code Playgroud)
但是我怎么能用镜头呢?以下不适用于发生的检查:
eg :: T a (b -> c) -> b -> T (a, b) c
eg t b = t & foo %~ (, b) & bar %~ uncurry
Run Code Online (Sandbox Code Playgroud)
使用自动生成的镜头无法做到这一点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))
Run Code Online (Sandbox Code Playgroud)
然后你可以(自动)构建变换镜头,T'并tt使用它们T a b通过同构来修改类型的值.
例如,重新排列参数,您可以编写
eg :: b -> T a (b -> c) -> T (a, b) c
eg b = over tt $ (foo' %~ (,b)) . (bar' %~ uncurry)
Run Code Online (Sandbox Code Playgroud)
这可能会更好,如果你不需要大惊小怪周围的另一种方法T太多是将其定义为一个newtype周围T':
newtype T a b = T { getT :: T' a b a }
Run Code Online (Sandbox Code Playgroud)
然后你可以跳过Iso并只是撰写东西.以相同的方式重新排列参数,
eg' :: b -> T a (b -> c) -> T (a, b) c
eg' b = T . (foo' %~ (,b)) . (bar' %~ uncurry) . getT
Run Code Online (Sandbox Code Playgroud)