首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何继续使用不同的参数调用函数,直到它在Haskell中成功

如何继续使用不同的参数调用函数,直到它在Haskell中成功
EN

Stack Overflow用户
提问于 2013-12-24 00:57:57
回答 2查看 215关注 0票数 2

我有一个函数,它调用另一个函数,根据特定的条件,这个函数可以返回某些内容,也可以不返回任何内容。我想知道的是,如果它不返回任何东西,我怎么用不同的参数再次调用它。

例如,我有一个函数,它可以以30分钟的间隔返回时间,而另一个函数只能在某个时间不返回任何内容,即:

代码语言:javascript
复制
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),然后触发函数返回第一个防护中的内容,然后整个周期应该结束。

EN

回答 2

Stack Overflow用户

发布于 2013-12-24 01:07:56

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

代码语言:javascript
复制
timeFunction :: (Int, Int, Int) -> (Int, Int, Int)
timeFunction time0 = case certainTimeFunction time0 of
  Nothing  -> timeFunction (perturbTime time0)
  Just res -> res

请注意,应该仔细调整perturbTimecertainTimeFunction以使它们协同工作,因为在这种情况下构建无限循环非常容易。一种更简洁的方法是使用iterate将递归“展开”到一个惰性列表中。

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

代码语言:javascript
复制
... iterate perturbTime :: [(Int, Int, Int)]

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

代码语言:javascript
复制
... map certainTimeFunction . iterate perturbTime :: [Maybe (Int, Int, Int)]

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

代码语言:javascript
复制
timeFunction = fromJust . head . dropWhile isNothing 
             . map certainTimeFunction 
             . iterate perturbTime

我们还可以创建一个版本的timeFunction,如果perturbTimen扰动中没有达到成功的点,这个版本就会失败

代码语言:javascript
复制
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
票数 6
EN

Stack Overflow用户

发布于 2013-12-24 01:14:26

如果你只想每隔30分钟给它喂一次,直到一个成功,你可以这样做

代码语言:javascript
复制
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更改为

代码语言:javascript
复制
times = takeWhile (\(h', _, _) -> h' < 24) $ iterate add30 initialTime

并将timeFunction的类型更改为Time -> Maybe String

这是一个很好的例子,说明了为什么应该定义自己的类型,而不是使用元组。如果你有

代码语言:javascript
复制
data Time = Time
    { hours :: Int
    , minutes :: Int
    , seconds :: Int
    } deriving (Eq, Show)

然后是一些辅助函数

代码语言:javascript
复制
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

它可以更简洁地写成

代码语言:javascript
复制
timeFunction = listToMaybe . catMaybes
             . map certainTimeFunction
             . takeWhile ((< 24) . hours)
             . iterate (+: asMinutes 30)

您还可以非常容易地使Time成为Ord的实例

代码语言:javascript
复制
instance Ord Time where
    compare = on compare toSeconds

timeFunction = listToMaybe . catMaybes
             . map certainTimeFunction
             . takeWhile (< asHours 24)
             . iterate (+: asMinutes 30)
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20747830

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档