我有一个函数,它调用另一个函数,根据特定的条件,这个函数可以返回某些内容,也可以不返回任何内容。我想知道的是,如果它不返回任何东西,我怎么用不同的参数再次调用它。
例如,我有一个函数,它可以以30分钟的间隔返回时间,而另一个函数只能在某个时间不返回任何内容,即:
certainTimeFunction :: (Int,Int,Int) -> Maybe String
certainTimeFunction (h,m,s) =
| (11,00,00) = Just "It's eleven o'clock"
| otherwise = Nothing
timeFunction :: (Int,Int,Int) -> (Int,Int,Int)
timeFunction time = certainTimeFunction time时间必须从(00,00,00)开始,它当然不会返回任何东西,但是然后尝试(00,30,00),它再次返回任何东西,直到(11,00,00),然后触发函数返回第一个防护中的内容,然后整个周期应该结束。
发布于 2013-12-24 01:07:56
和在Haskell中一样,答案是使用递归!
timeFunction :: (Int, Int, Int) -> (Int, Int, Int)
timeFunction time0 = case certainTimeFunction time0 of
Nothing -> timeFunction (perturbTime time0)
Just res -> res请注意,应该仔细调整perturbTime和certainTimeFunction以使它们协同工作,因为在这种情况下构建无限循环非常容易。一种更简洁的方法是使用iterate将递归“展开”到一个惰性列表中。
首先,我们创建一个“所有扰动”的无限列表
... iterate perturbTime :: [(Int, Int, Int)]然后我们map certainTimeFunction来检查是否有任何这样的扰动返回Just。
... map certainTimeFunction . iterate perturbTime :: [Maybe (Int, Int, Int)]然后,我们可以通过删除所有Nothing来恢复timeFunction的确切行为。
timeFunction = fromJust . head . dropWhile isNothing
. map certainTimeFunction
. iterate perturbTime我们还可以创建一个版本的timeFunction,如果perturbTime在n扰动中没有达到成功的点,这个版本就会失败
timeFunctionN n = safeJustHead
. dropWhile isNothing
. take n
. map certainTimeFunction
. iterate perturbTime
where safeJustHead :: [Maybe a] -> Maybe a -- note this is just `msum`
safeJustHead [] = Nothing -- it's also easy to implement
safeJustHead (x:_) = x -- using `Data.Maybe.listToMaybe`
-- per @bheklilr's comment below发布于 2013-12-24 01:14:26
如果你只想每隔30分钟给它喂一次,直到一个成功,你可以这样做
import Data.Maybe
timeFunction :: (Int, Int, Int) -> (Int, Int, Int)
timeFunction initialTime = head $ catMaybes $ map certainTimeFunction times
where
add30 (h, m, s) =
let newM = m + 30
newH = h + newM `div` 60
in (newH, newM `mod` 60, s)
times = iterate add30 initialTime这将懒惰地计算从初始时间开始的所有30分钟的增量(我的add30是@JAbrahamson的perturbTime),然后certainTimeFunction被映射到所有这些时间,然后catMaybes将其压缩为Just值(再次懒惰地),取第一个值。请注意,如果您没有获得certainTimeFunction返回成功值的时间,这将永远循环!
如果您想在超过23小时后停止,只需使用我们的好朋友takeWhile并将times更改为
times = takeWhile (\(h', _, _) -> h' < 24) $ iterate add30 initialTime并将timeFunction的类型更改为Time -> Maybe String
这是一个很好的例子,说明了为什么应该定义自己的类型,而不是使用元组。如果你有
data Time = Time
{ hours :: Int
, minutes :: Int
, seconds :: Int
} deriving (Eq, Show)然后是一些辅助函数
import Data.Function (on)
asSeconds :: Int -> Time
asSeconds x = Time (x `div` 3600) (x `div` 60 `mod` 60) (x `mod` 60)
asMinutes :: Int -> Time
asMinutes = asSeconds . (* 60)
asHours :: Int -> Time
asHours x = asMinutes . (* 60)
toSeconds :: Time -> Int
toSeconds (Time h m s) = h * 3600 + m * 60 + s
(+:) :: Time -> Time
(+:) = asSeconds .: on (+) toSeconds where (.:) = (.).(.)
timeFunction :: Time -> Maybe Time
timeFunction initialTime = listToMaybe $ catMaybes $ map certainTimeFunction times
where
times = takeWhile ((< 23) . hours) $ iterate (+: asMinutes 30) initialTime它可以更简洁地写成
timeFunction = listToMaybe . catMaybes
. map certainTimeFunction
. takeWhile ((< 24) . hours)
. iterate (+: asMinutes 30)您还可以非常容易地使Time成为Ord的实例
instance Ord Time where
compare = on compare toSeconds
timeFunction = listToMaybe . catMaybes
. map certainTimeFunction
. takeWhile (< asHours 24)
. iterate (+: asMinutes 30)https://stackoverflow.com/questions/20747830
复制相似问题