What is the correct way to perform constant-space nested loops in Haskell?

后端 未结 2 922
感动是毒
感动是毒 2021-02-02 11:43

There are two obvious, \"idiomatic\" ways to perform nested loops in Haskell: using the list monad or using forM_ to replace traditional fors. I\'ve se

2条回答
  •  抹茶落季
    2021-02-02 12:32

    In my experience forM_ [0..n-1] can perform well, but unfortunately it's not reliable. Just adding an INLINE pragma to test_a and using -O2 makes it run much faster (4s to 1s for me), but manually inlining it (copy paste) slows it down again.

    A more reliable function is is for from statistics which is implemented as

    -- | Simple for loop.  Counts from /start/ to /end/-1.
    for :: Monad m => Int -> Int -> (Int -> m ()) -> m ()
    for n0 !n f = loop n0
      where
        loop i | i == n    = return ()
               | otherwise = f i >> loop (i+1)
    {-# INLINE for #-}
    

    Using it looks similar to forM_ with lists:

    test_d :: MV.IOVector Int -> IO ()
    test_d mv =
      for 0 times $ \_ ->
        for 0 side $ \i ->
          for 0 side $ \j ->
            MV.unsafeWrite mv (i*side + j) 1
    

    but performs reliably well (0.85s for me) without any risk of allocating a list.

提交回复
热议问题