gpt4 book ai didi

haskell - 我应该使用什么递归方案来重复有效的操作,直到其结果符合某些标准?

转载 作者:行者123 更新时间:2023-12-02 21:25:47 25 4
gpt4 key购买 nike

也就是说,我要问的是一个循环。

effectful :: Int -> IO Int
effectful n = do
putStrLn $ "Effect: " ++ show n
return n

condition = (== 3)

final :: Int -> IO ()
final n = putStrLn $ "Result: " ++ show n

loop = ?

它应该像这样工作:

λ loop [1..10]
Effect: 1
Effect: 2
Effect: 3
Result: 3

我可以提供一个递归定义:

loop (x: xs) = do
r <- effectful x
if condition r
then final r
else loop xs

但是,我无法用 FunctorMonadFoldableTraversable 方法,因为它们始终坚持评估所有操作,而我需要的是在列表中的某个点停止。

例如,使用 unfoldrM (这是我使用的 Data.List.unfoldr 的有效版本)弥补了这个场合)我可以准确地执行我需要的操作,但我无法获得值(value)最后一个操作的结果,因为函数参数返回 Nothing:

unfoldrM :: Monad m => (a -> MaybeT m (b, a)) -> a -> m [b]
unfoldrM f x = fmap reverse $ unfoldrM' f x (return [ ])
where
-- unfoldrM' :: (a -> MaybeT m (b, a)) -> a -> m [b] -> m [b]
unfoldrM' f x ys = runMaybeT (f x) >>= \r -> case r of
Just (y, x') -> unfoldrM' f x' (fmap (y:) ys)
Nothing -> ys

f :: [Int] -> MaybeT IO (Int, [Int])
f (x: xs) = (lift . effectful $ x) >>= \y ->
if condition y
then MaybeT (return Nothing)
else lift . return $ (y, xs)

— 这让我思考:“如果我使用 Either 代替,然后展开 Left 结果会怎样?”这种考虑使我想到了 Control.Monad.Except ,然后想到我应该将期望的结果视为控制流中的异常

exceptful :: Int -> ExceptT Int IO ()
exceptful n = do
r <- lift (effectful n)
if condition r
then throwError r
else return ()

loop' xs = fmap (fromRight ())
$ runExceptT (traverse_ exceptful xs `catchError` (lift . final))

 

λ loop' [1..10]
Effect: 1
Effect: 2
Effect: 3
Result: 3

我认为这个解决方案很糟糕。首先,使用左侧作为实际结果载体,其次,这段代码比我开始使用的递归循环

可以做什么?

最佳答案

我喜欢将此类任务建模为涉及有效流的函数。 streaming package 对此很有帮助,因为它提供了一个与传统的纯列表非常相似的 api。 (也就是说,Functor/Applicative/Monad 实例有点不同:它们通过 Stream 工作”连接“,而不是像纯列表那样探索所有组合。)

例如:

import Streaming
import qualified Streaming.Prelude as S

loop :: Int -> (a -> Bool) -> IO a -> IO (Maybe a)
loop limit condition = S.head_ . S.filter condition . S.take limit . S.repeatM

使用repeatM , take , filterhead_来自“流”的功能。

或者,如果我们有一个有效的函数和一个值列表:

loop :: (b -> Bool) -> (a -> IO b) -> [a] -> IO (Maybe b)
loop condition effectful = S.head_ . S.filter condition . S.mapM effectful . S.each

使用eachmapM来自“流媒体”。

如果我们想执行最终有效的操作:

loop :: (b -> IO ()) -> (b -> Bool) -> (a -> IO b) -> [a] -> IO ()
loop final condition effectful =
S.mapM_ final . S.take 1 . S.filter condition . S.mapM effectful . S.each

使用mapM_来自“流媒体”。

关于haskell - 我应该使用什么递归方案来重复有效的操作,直到其结果符合某些标准?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57347510/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com