如何在Haskell成功之前继续调用具有不同参数的函数

use*_*936 2 haskell function

我有一个函数,它调用另一个函数,可以根据某些条件返回一些东西或什么都没有.我想知道的是,如果它什么都不返回,我怎么用不同的参数再次调用它.

比方说,我有一个函数可以以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
Run Code Online (Sandbox Code Playgroud)

时间必须从(00,00,00)开始,当然它将返回Nothing但是然后(00,30,00)被尝试再次返回Nothing直到(11,00,00)然后触发函数返回什么在第一个守卫,那么整个周期应该结束.

J. *_*son 6

和Haskell一样,答案是使用递归!

timeFunction :: (Int, Int, Int) -> (Int, Int, Int)
timeFunction time0 = case certainTimeFunction time0 of
  Nothing  -> timeFunction (perturbTime time0)
  Just res -> res
Run Code Online (Sandbox Code Playgroud)

请注意,perturbTime并且certainTimeFunction应该仔细调整以协同工作,因为在这样的环境中构建无限循环非常容易.更简洁的方法是使用将"递归""展开"到一个惰性列表中iterate.

首先,我们创建一个"所有扰动"的无限列表

... iterate perturbTime :: [(Int, Int, Int)]
Run Code Online (Sandbox Code Playgroud)

然后我们map certainTimeFunction检查是否有任何这样的扰动返回Just.

... map certainTimeFunction . iterate perturbTime :: [Maybe (Int, Int, Int)]
Run Code Online (Sandbox Code Playgroud)

然后我们可以timeFunction通过删除所有Nothings 来恢复确切的行为.

timeFunction = fromJust . head . dropWhile isNothing 
             . map certainTimeFunction 
             . iterate perturbTime
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 你是一个比我更快的打字员,而且你有一个更全面的答案.另外,为什么不使用`Data.Maybe.listToMaybe`函数而不是定义自己的`safeHead`?它做同样的事情. (2认同)