2014-01-21 4 views
3

지금은 WorkLog 유형으로 시작일과 종료일이 있습니다. 또한 기간 렌즈를 추가하여 시작일과 종료일에서 파생됩니다. 읽기 전용이거나 값이 변경되면 종료 날짜를 변경해야합니다 (두 버전을 구현하는 방법을 알고 싶습니다. 단 하나만 사용 하겠지만).렌즈 라이브러리를 사용하여 다른 렌즈에 의존하는 복잡한 렌즈를 어떻게 작성합니까?

여기 내 코드입니다. 기본적으로, 당신은 과 workLogDurationRW 주요 통과에서 모든 테스트를 얻을 구현할 수 있다면, 내 질문에 대답 것입니다.

{-# LANGUAGE TemplateHaskell #-} 
module Main where 
import Control.Lens 

-- Keep times simple for this example 
newtype TimeStamp = TimeStamp Int deriving (Show, Eq) 
newtype TimeDifference = TimeDifference Int deriving (Show, Eq) 

(-.-) :: TimeStamp -> TimeStamp -> TimeDifference 
(TimeStamp a) -.- (TimeStamp b) = TimeDifference (a - b) 

data WorkLog = WorkLog { 
    _workLogDescription :: String 
    , _workLogStartTime :: TimeStamp 
    , _workLogEndTime :: TimeStamp 
    } 

makeLenses ''WorkLog 

-- | Just return the difference between the start and end time 
workLogDurationRO :: Getter WorkLog TimeDifference 
workLogDurationRO = error "TODO write me!" 

-- | Like the read only version, but when used with a setter, 
-- change the end date. 
workLogDurationRW :: Lens' WorkLog TimeDifference 
workLogDurationRW = error "TODO write me!" 

ensure :: String -> Bool -> IO() 
ensure _ True = putStrLn "Test Passed" 
ensure msg False = putStrLn $ "Test Failed: " ++ msg 

main :: IO() 
main = do 
    let testWorkLog = WorkLog "Work 1" (TimeStamp 40) (TimeStamp 100) 
    ensure "read only lens gets correct duration" $ 
    testWorkLog^.workLogDurationRO == TimeDifference 60 
    ensure "read+write lens gets correct duration" $ 
    testWorkLog^.workLogDurationRW == TimeDifference 60 
    let newWorkLog = testWorkLog & workLogDurationRW .~ TimeDifference 5 
    ensure "writeable lens changes end time" $ 
    newWorkLog^.workLogEndTime == TimeStamp 45 

답변

6

당신은 Getterto가 (당신이 괄호를 제거하는 -.- 낮은 우선 순위를 줄 수)를 사용하여 작성할 수 있습니다

workLogDurationRO = to $ \wl -> (wl^.workLogEndTime) -.- (wl^.workLogStartTime) 

그러나 lens wiki 말한대로, 당신이 형편이 아마 더 좋을 것 같아

시차를 계산하는 일반 함수로, 렌즈로 필요할 때 to과 함께 사용할 수 있습니다.

당신은 (위와 동일) 게터에서 Lens'와 세터 구축 할 수 있습니다 :

workLogDurationRW = lens get set 
    where 
    get :: WorkLog -> TimeDifference 
    get wl = (wl^.workLogEndTime) -.- (wl^.workLogStartTime) 

    set :: WorkLog -> TimeDifference -> WorkLog 
    set wl timeDiff = wl & workLogEndTime .~ (wl^.workLogStartTime) +.+ timeDiff 
     where 
     TimeStamp a +.+ TimeDifference b = TimeStamp (a + b) 
+0

덕분에, (이 가늠자에 분명하다하더라도) 렌즈 기능을 사용하여 생각하지 않았다을 . 아직도이 도서관 주위에 내 머리를지고 :) –

1
workLogDurationRO :: Getter WorkLog TimeDifference 
workLogDurationRO f [email protected](WorkLog d s e) = fmap (const w) (f $ e -.- s) 


workLogDurationRW :: Lens' WorkLog TimeDifference 
workLogDurationRW f (WorkLog d [email protected](TimeStamp y) e) = 
    fmap (\(TimeDifference x) -> WorkLog d s (TimeStamp $ y + x)) (f $ e -.- s) 
관련 문제