我正在创建一个验证时间的程序。我有以下代码:
data TimeError
= WrongHour Int
| WrongMinute Int
deriving (Eq, Show)
lookHour :: Int -> Validation [TimeError] Int
lookHour n
| n < 0 = Failure[WrongHour n]
| n > 23 = Failure[WrongHour n]
| otherwise = Success n
lookMinute :: Int -> Validation [TimeError] Int
lookMinute n
| n < 0 = Failure[WrongMinute n]
| n > 59 = Failure[WrongMinute n]
| otherwise = Success n
lookTime :: (Int, Int) -> Validation [TimeError] Time
lookTime (h, m) = Time <$> lookHour h <*> lookMinute m
lookAllTimes :: [(Int, Int)] -> Validation [TimeError] AllTimes
lookAllTimes [] = Success (AllTimes [])
lookAllTimes (x:xs) = AllTimes <$> lookTime x <*> lookAllTimes xs
函数 lookAllTimes
应该在时间列表中使用 lookTime
来返回结果,但它不起作用。
回答1
您没有发布 Time
和 AllTimes
的定义,但我猜它们如下:
data Time = Time Int Int deriving (Eq, Show)
newtype AllTimes = AllTimes [Time] deriving (Eq, Show)
鉴于它们,问题在于 lookAllTimes
的缺点。具体来说,您不会在那里调用 (:)
来将列表重新组合在一起,并且您也不会从尾部删除 AllTimes
包装器。用这个替换你的最后一行:
lookAllTimes (x:xs) = (\y (AllTimes ys) -> AllTimes (y:ys)) <$> lookTime x <*> lookAllTimes xs
您还可以通过利用列表的 Traversable
实例来简化整个 lookAllTimes
函数,不过,如下所示:
lookAllTimes :: [(Int, Int)] -> Validation [TimeError] AllTimes
lookAllTimes = fmap AllTimes . traverse lookTime
这基本上意味着“在每个列表元素上执行 lookTime
,然后将成功的结果包装在 AllTimes
中”。