代码之家  ›  专栏  ›  技术社区  ›  sastanin

用折叠组合单子动作

  •  4
  • sastanin  · 技术社区  · 16 年前

    (Monad m) => a -> m a . 例如:

    ghci> let f x = Just (x+1)
    

    ghci> let times n f = foldr (>=>) return $ replicate n f
    

    问题是它在大范围内不起作用 n :

    ghci> 3 `times` f $ 1
    Just 4
    ghci> 1000000 `times` f $ 1
    Just *** Exception: stack overflow
    

    另一方面,它也不起作用:

    ghci> let timesl n f = foldl' (<=<) return $ replicate n f
    ghci> 3 `timesl` f $ 1
    Just 4
    ghci> 1000000 `timesl` f $ 1
    Just *** Exception: stack overflow
    

    ($!)

    ghci> let timesStrict n f = foldr1 ((>=>) . ($!)) $ replicate n f
    ghci> 3 `timesStrict` f $ 1
    Just 4
    ghci> 10000000 `timesStrict` f $ 1
    Just 10000001
    

    有更好或更惯用的解决方案吗?还是更严格的?如果 f 是一个很重的函数。

    UPD: 我发现那是一种写作 times 以一种有意义的形式,也不能解决构成重量级一元动作的问题。这对fx=Just(x+1)有效,但在现实世界中失败:

    times f 0 a = return a
    times f i a = (f $! a) >>= times f (i - 1)
    
    3 回复  |  直到 16 年前
        1
  •  4
  •   Greg Bacon    16 年前

    如果你 f 严格的

    f x = let y = x+1 in y `seq` Just y
    

    -- remember to enable -XBangPatterns
    f !x = Just (x+1)
    

    剩下的就不用管了,你的代码在恒定的空间中运行(尽管速度很慢),即使是非常大的空间 n :

    ghci> times 4000000000 f 3
    Just 4000000003
        2
  •  2
  •   ephemient    16 年前

    {-# LANGUAGE BangPatterns #-}
    iterate' f !x = x : iterate' f (f x)
    ma >>=! f = do !a <- ma; f a
    times' n f a = iterate' (>>=! f) (return a) !! n
    

    seq 仅计算WHNF的第一个参数?如果你在一个复杂的结构上工作,你可能需要更深入的研究 序号 喜欢 deepseq .

        3
  •  1
  •   liwp    16 年前

    我想到了这个:

     last $ take n $ iterate (>>= f) $ Just 1
    

    但它也会在大量的数据上溢出堆栈 n . 我现在没有时间进一步调查:-(