validation - Haskell 中的列表 validation 有问题

我正在创建一个验证时间的程序。我有以下代码:

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

您没有发布 TimeAllTimes 的定义,但我猜它们如下:

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 中”。

相似文章