切断惰性列表生成

发布于 2024-10-17 09:50:03 字数 423 浏览 5 评论 0原文

我想知道是否有人对如何创建一个函数有任何见解,该函数将接受一个列表并仅返回可以在 x 时间内生成的术语。

例如,我有一个函数需要大约 10 分钟才能返回几个术语。我不想猜测我能够生成多少项(使用 take x),而是想将一个无限列表输入到我的低效函数中,并让一个单独的函数决定何时超时。

所以像这样: [5,7,10] = takeUntilTime (10 sec) 。 inefficientFunction $ [1..]

我对 haskell 还很陌生,但我想我可以编写该函数来在每个新术语生成后检查计时器,并在时间已过时停止。

但是,如果第四个任期需要永恒怎么办?有没有办法阻止 inefficientFunction 完成第四项的生成,即使它已经开始了?

我对直接答案不抱太大希望,但我很欣赏对此的任何直觉。谢谢。

I was wondering if anyone has any insights on how to make a function that will take a list and only return the terms that can be generated in x amount of time.

For instance, I have a function that takes something like 10 minutes to return only a few terms. Instead of guessing how many terms I'd be able to generate (with take x), I'd like to just feed in an infinite list into my inefficient function and have a separate function decide when to time out.

So something like this: [5,7,10] = takeUntilTime (10 sec) . inefficientFunction $ [1..]

I'm pretty new to haskell, but I think I can write that function to just check the timer after each new term is generated and stopping if the time has elapsed.

However, what if the 4th term takes an eternity? Would there be a way to stop the inefficientFunction from finishing the generation of that 4th term even though it has already started?

I don't have high hopes for a straightforward answer, but I appreciate any intuition on this. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

橘香 2024-10-24 09:50:03

还没有经过太多测试,但这似乎有效,至少在小范围内有效。

import Control.Concurrent
import Control.Exception
import Control.Monad

takeUntilTime :: Int -> [a] -> IO [a]
takeUntilTime limit list = do
    me <- myThreadId
    bracket (forkIO $ threadDelay limit >> throwTo me NonTermination) killThread
        . const $ tryTake list
  where
    (/:/) = liftM2 (:)
    tryTake list = handle (\NonTermination -> return []) $
        case list of
            [] -> return []
            x:xs -> evaluate x /:/ tryTake xs
ghci> takeUntilTime 1000000 [x | x <- [1..], x == 0]
[]
(1.02 secs, 153111264 bytes)
ghci> takeUntilTime 1000000 [maximum [y `mod` x | y <- [1..100000]] | x <- [1..]]
[0,1,2,3]
(1.00 secs, 186234264 bytes)

Haven't put it through much testing, but this seems to work, at least on a small scale.

import Control.Concurrent
import Control.Exception
import Control.Monad

takeUntilTime :: Int -> [a] -> IO [a]
takeUntilTime limit list = do
    me <- myThreadId
    bracket (forkIO $ threadDelay limit >> throwTo me NonTermination) killThread
        . const $ tryTake list
  where
    (/:/) = liftM2 (:)
    tryTake list = handle (\NonTermination -> return []) $
        case list of
            [] -> return []
            x:xs -> evaluate x /:/ tryTake xs
ghci> takeUntilTime 1000000 [x | x <- [1..], x == 0]
[]
(1.02 secs, 153111264 bytes)
ghci> takeUntilTime 1000000 [maximum [y `mod` x | y <- [1..100000]] | x <- [1..]]
[0,1,2,3]
(1.00 secs, 186234264 bytes)
长梦不多时 2024-10-24 09:50:03

我认为你想要的是这样的: System.Timeout

它允许IO事件超时。它有一个函数,其类型为:

timeout :: Int -> IO a -> IO (Maybe a)

我认为你应该能够使用它。我的方法是使用超时函数和迭代深化方法将越来越多的内容输入到您的函数中,直到它起作用。这样,当一个人最终超时时,你就知道你已经走得足够远了。

I think what you want is this: System.Timeout

It allows IO events to time out. It has a function whose type is:

timeout :: Int -> IO a -> IO (Maybe a)

I think you should be able to use that. The way that I would do it is to use the timeout function and the Iterative Deepening approach to feed more and more into your function until it works. That way, when one finally hits the timeout you know that you have gone far enough.

表情可笑 2024-10-24 09:50:03

我认为你问了两个问题。
1. 如何设置从无限列表中获取元素的时间限制。
2. 如何终结一个阻塞函数,或者创建一个非阻塞函数,比如一些网络IO函数。

第二个可以参考http://twelvestone.com/forum_thread/view/32028 一些想法。
那么对于第一个,您可以假设 inefficientFunction 是非阻塞的。

I think you asked two questions.
1. How to set time limit for taking elements from infinite list.
2. How to terminal a blocking function, or create a non-blocking function, like some network IO functions.

For the second one, you can refer to http://twelvestone.com/forum_thread/view/32028 for some idea.
Then for the first one, you can suppose as a fact that inefficientFunction is non-blocking.

星星的轨迹 2024-10-24 09:50:03

受到 ephemient 的回答的启发,我想我应该发布他的解决方案的两个概括。

解决方案 1

import Control.Concurrent
import Control.Exception
import Control.Monad

doUntilTime :: Int -> IO a {- must handle NonTermination exception! -} -> IO a
doUntilTime limit action = do
  me <- myThreadId
  bracket (forkIO $ threadDelay limit >> throwTo me NonTermination) killThread
           . const $ action

示例

(/:/) = liftM2 (:)
tryTake list = handle (\NonTermination -> return []) $
   case list of
     [] -> return []
     x:xs -> evaluate x /:/ tryTake xs

test = do
  res <- doUntilTime 1000000 (tryTake [1..])
  putStrLn (show $ length res)

解决方案 2

在此解决方案中,您将一个默认值、一个输入和一个预递归函数传递给doUntilTime< /代码>。

预递归函数的编写风格是第一个参数(我们称之为 self),用于之前使用递归调用的地方。这使您不必显式处理 NonTermination 异常。

import Control.Concurrent
import Control.Exception
import Control.Monad

doUntilTime :: Int -> a -> b -> ((a -> IO b) -> (a -> IO b)) -> IO b
doUntilTime limit input defaultVal action = do
    me <- myThreadId
    bracket (forkIO $ threadDelay limit >> throwTo me NonTermination) killThread
        . const $ fix action input
  where
    fix f = f (\a -> handle (\NonTermination -> return defaultVal) (fix f a))

(/:/) = liftM2 (:)

-- tryTake is written in a "pre-recursive" style. There are no
-- occurrences of "tryTake" in the body only occurrences of
-- "self" (the first parameter)
tryTake :: ([Int] -> IO [Float]) -> ([Int] -> IO [Float])
tryTake self list =
   case list of
     [] -> return []
     x:xs -> evaluate (fromIntegral x) /:/ self xs

test = do
  res <- doUntilTime 1000000 [1..] [] tryTake
  print (length res)

Inspired by ephemient's answer I thought I'd post two generalisations of his solution.

Solution 1

import Control.Concurrent
import Control.Exception
import Control.Monad

doUntilTime :: Int -> IO a {- must handle NonTermination exception! -} -> IO a
doUntilTime limit action = do
  me <- myThreadId
  bracket (forkIO $ threadDelay limit >> throwTo me NonTermination) killThread
           . const $ action

Example

(/:/) = liftM2 (:)
tryTake list = handle (\NonTermination -> return []) $
   case list of
     [] -> return []
     x:xs -> evaluate x /:/ tryTake xs

test = do
  res <- doUntilTime 1000000 (tryTake [1..])
  putStrLn (show $ length res)

Solution 2

In this solution you pass a default value, an input, and a pre-recursive function to doUntilTime.

The pre-recursive function is written in a style where the first parameter, let's call it self, is used where you would have used a recursive call before. This saves you having to handle the NonTermination exception explicitly.

import Control.Concurrent
import Control.Exception
import Control.Monad

doUntilTime :: Int -> a -> b -> ((a -> IO b) -> (a -> IO b)) -> IO b
doUntilTime limit input defaultVal action = do
    me <- myThreadId
    bracket (forkIO $ threadDelay limit >> throwTo me NonTermination) killThread
        . const $ fix action input
  where
    fix f = f (\a -> handle (\NonTermination -> return defaultVal) (fix f a))

(/:/) = liftM2 (:)

-- tryTake is written in a "pre-recursive" style. There are no
-- occurrences of "tryTake" in the body only occurrences of
-- "self" (the first parameter)
tryTake :: ([Int] -> IO [Float]) -> ([Int] -> IO [Float])
tryTake self list =
   case list of
     [] -> return []
     x:xs -> evaluate (fromIntegral x) /:/ self xs

test = do
  res <- doUntilTime 1000000 [1..] [] tryTake
  print (length res)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文