目前,我有WorkLog
类型,包含开始日期和结束日期。我还要添加一个持续时间镜头,它将从开始和结束日期派生。它应该是只读的,或者如果它的值被改变就改变结束日期(我想知道如何实现这两个版本,即使我只使用一个)。
这是我的代码。基本上,如果您可以实现workLogDurationRO
和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
答案 0 :(得分:6)
您可以使用Getter
编写to
(您可以使-.-
优先级更低,以摆脱括号):
workLogDurationRO = to $ \wl -> (wl^.workLogEndTime) -.- (wl^.workLogStartTime)
但正如lens wiki所说,你可能会更好地使用计算时差的正常函数,然后当你需要它作为镜头时,你可以使用to
。
您可以从getter(与上面相同)和setter构建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)
答案 1 :(得分:1)
workLogDurationRO :: Getter WorkLog TimeDifference
workLogDurationRO f w@(WorkLog d s e) = fmap (const w) (f $ e -.- s)
workLogDurationRW :: Lens' WorkLog TimeDifference
workLogDurationRW f (WorkLog d s@(TimeStamp y) e) =
fmap (\(TimeDifference x) -> WorkLog d s (TimeStamp $ y + x)) (f $ e -.- s)