You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

询问是否存在定时重复执行功能及Haskell库提供repeatEvery函数

有没有Haskell库提供「每隔指定时间重复执行动作」的功能?

我在优化自己试验的Haskell通知服务器时,手写了下面这段代码:

import Control.Concurrent (threadDelay)
import Control.Monad (forever)
repeatEvery :: Int -> IO () -> IO ()
repeatEvery time action = forever $ action >> threadDelay time

使用方式如下:

repeatEvery oneSec $ do
  stuff

我想知道有没有现成的Haskell库暴露了类似repeatEvery的函数——我在Hoogle上搜索类型签名a -> f b -> f b没找到相关结果,会不会是这类函数的类型签名和我写的不一样?


相关库中的实现

1. async库的repeatedly

async库提供了repeatedly函数,它会无限重复执行传入的IO动作,但没有直接的间隔时间参数。你可以把动作和threadDelay打包后传入,间接实现定时重复:

import Control.Concurrent (threadDelay)
import Control.Concurrent.Async (repeatedly)

repeatEvery time action = repeatedly $ action >> threadDelay time

它的类型签名是:

repeatedly :: IO a -> IO b

2. schedule库

schedule库专注于定时任务调度,支持固定间隔、Cron表达式等多种调度规则。其中scheduleAction可以实现你的需求:

import qualified Schedule as S

main = do
  let action = putStrLn "执行定时任务"
  -- 每隔1秒执行一次
  S.scheduleAction (S.everySeconds 1) action
  -- 阻塞等待调度任务执行
  S.waitForSchedule

3. time-manager库

这个库的repeatAction直接支持指定间隔时间,类型签名更贴合你的需求:

repeatAction :: NominalDiffTime -> IO () -> IO ()

使用时需要用NominalDiffTime类型定义间隔(以秒为单位的浮点数):

import Data.Time.Clock (secondsToNominalDiffTime)
import Time.Manager (repeatAction, withTimeManager)

main = withTimeManager $ \tm -> do
  let oneSec = secondsToNominalDiffTime 1
  repeatAction oneSec (putStrLn "每隔1秒执行一次")

4. 基于base库的优化版本

你自己手写的实现已经足够简洁,如果不想引入额外依赖,可以优化时间单位的可读性,用标准库的时间类型替代原始的微秒整数:

import Control.Concurrent (threadDelay)
import Control.Monad (forever)
import Data.Time.Clock (NominalDiffTime, diffTimeToPicoseconds)

repeatEvery :: NominalDiffTime -> IO () -> IO ()
repeatEvery delay action = forever $ do
  action
  -- 将NominalDiffTime转换为微秒,适配threadDelay的参数要求
  threadDelay $ fromIntegral $ diffTimeToPicoseconds delay `div` 1000000

内容的提问来源于stack exchange,提问作者Enlico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:03:32