Kat*_* J. 7 haskell types haskell-lens
我们A, B, C是类型,有两个功能f :: (A , B) -> A和g :: (A , B) -> B.考虑以下记录类型
data Rec = Rec{_a :: A, _b :: B, _c :: C}.
定义映射(Rec a b c)到(Rec (f a b) (g a b) c)使用lens组合器的函数的最优雅方法是什么?
镜头a,b并且c将用手写出fmap(<&>是中缀翻转fmap)
a :: Functor f => (A -> f A) -> Rec -> f Rec
a f (Rec a b c) = f a <&> \a' -> Rec a' b c
b :: Functor f => (B -> f B) -> Rec -> f Rec
b f (Rec a b c) = f b <&> \b' -> Rec a b' c
c :: Functor f => (C -> f C) -> Rec -> f Rec
c f (Rec a b c) = f c <&> \c' -> Rec a b c'
Run Code Online (Sandbox Code Playgroud)
正如cchalmers指出的那样,我们可以扩展这种模式,同时为场_a和_b场写镜头
ab :: Functor f => ((A, B) -> f (A, B)) -> Rec -> f Ref
ab f (Rec a b c) = f (a,b) <&> \(a',b') -> Rec a' b' c
Run Code Online (Sandbox Code Playgroud)
结合&&&from Control.Arrow,%~我们可以优雅地编写所需的功能
inAB :: ((A, B) -> A) -> ((A, B) -> B) -> Rec -> Rec
inAB f g = ab %~ (f &&& g)
Run Code Online (Sandbox Code Playgroud)
如果您对镜头库非常熟悉,您可能更愿意使用(ab %~ (f &&& g))而不是inAB f g.
有不是一个镜头用于构建的透镜功能ab从透镜a和b自两个透镜的产品一般在相同的基础结构不为产品到所述一个底层结构的透镜; 两个镜头都可能试图改变相同的底层场并违反镜头规律.
如果没有镜头,您可以定义一个函数将函数应用于 记录的字段_a和_b字段.
onAB :: (A -> B -> c) -> Rec -> c
onAB f r = f (_a r) (_b r)
Run Code Online (Sandbox Code Playgroud)
修饰两者的函数_a和_b基于每个功能字段只是设置_a和_b对施加到字段中的两个函数的结果.
inAB' :: (A -> B -> A) -> (A -> B -> B) -> Rec -> Rec
inAB' f g r = r {_a = onAB f r, _b = onAB g r}
Run Code Online (Sandbox Code Playgroud)
折腾了几下,curry我们得到了你想要的类型签名
inAB :: ((A, B) -> A) -> ((A, B) -> B) -> Rec -> Rec
inAB f g = inAB' (curry f) (curry g)
Run Code Online (Sandbox Code Playgroud)
随着镜头,我们也可以说,我们是set荷兰国际集团a和b.它不比使用记录构造函数更优雅,它需要构造两次记录.
inAB' :: (A -> B -> A) -> (A -> B -> B) -> Rec -> Rec
inAB' f g r = set b (onAB g r) . set a (onAB f r) $ r
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
165 次 |
| 最近记录: |