3

現時点ではWorkLog、開始日と終了日を持つタイプがあります。開始日と終了日から派生する期間レンズも追加したいと思います。読み取り専用にするか、値が変更された場合は終了日を変更する必要があります (1 つしか使用しませんが、両方のバージョンを実装する方法を知りたいです)。

これが私のコードです。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
4

2 に答える 2

6

Getterusing を書くことができtoます (-.-括弧を取り除くために優先度を下げることができます):

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

しかし、lens wikiが言うように、時間差を計算する通常の関数を使用したほうがよいでしょうto。これは、レンズとして必要なときに使用できます。

Lens'getter (上記と同じ) と setter からを構築できます。

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)
于 2014-01-21T12:50:38.023 に答える
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)
于 2014-01-21T12:52:43.477 に答える