Haskell镜头-棱镜组成

时间:2018-08-17 08:54:47

标签: haskell lens

我正在尝试在Haskell中编写镜头和棱镜,但没有得到我期望的答案。这是我的测试代码:

{-# LANGUAGE OverloadedStrings #-}
import Data.Function  ( ($), (&) )

import Control.Lens.Getter  ( (^.) )
import Control.Lens.Lens    ( Lens', lens )
import Control.Lens.Prism   ( Prism', prism )
import Control.Lens.Setter  ( (.~) )
import Control.Lens.Review  ( AReview, re )
import Control.Lens.TH      ( makeClassy )

(##) :: AReview t s -> s -> t
x ## y = y ^. re x

data Test = T1 Int | T2 String
  deriving Show

_T1 :: Prism' Test Int
_T1 = prism T1 (\x -> case x of T1 i -> Right i; _ -> Left x)

_T2 :: Prism' Test String
_T2 = prism T2 (\x -> case x of T2 t -> Right t; _ -> Left x)

data Combi = Combi { _t :: Test }
  deriving Show

defCombi :: Combi
defCombi = Combi (T1 7)

t :: Lens' Combi Test
t = lens (\(Combi x) -> x) (\( Combi _ ) t' -> Combi t')

test = (defCombi & t .~ (_T2 ## "foo"), defCombi & (t . _T2) .~ "bar")

现在让我惊讶的是,当我运行此命令时,第二对显示Combi {_t = T1 7};也就是说,通过t进行“赋值”。 _T2无效。

从类型上看,显然相关的细节是将t与_T2组合将“ Functor”需求提升为“ Applicative”需求。

*Main
λ> :t t
t :: Functor f => (Test -> f Test) -> Combi -> f Combi
*Main
λ> :t t . _T2
t . _T2
  :: Applicative f => (String -> f String) -> Combi -> f Combi

但坦率地说,我无法理解这意味着什么,尤其是为什么这意味着该合成不“起作用”(或更可能它确实起作用了,但是我误解了什么)在此情况下表示)。

所有的启蒙运动都感激不尽。

1 个答案:

答案 0 :(得分:1)

使用Prism或实际上的任何Traversal作为设置器时,仅当参数已经在正确的变体上时,它才有效。

Prelude> :module + Control.Lens

Prelude Control.Lens> (Left 4) & (_Left .~ "foo")
Left "foo"

Prelude Control.Lens> (Left 4) & (_Right .~ "foo")
Left 4

因此,将_T2 .~ "bar"应用于T1 7会得到T1 7而不是T2 "bar"