
Hello, a friend and I were recently experimenting with mutable arrays. We tried to implement a simple dot product on STUArrays using a 'while' loop. Unfortunately, every implementation we produced caused a stack overflow. Switching to other implementations of 'while' or to IOUArrays did not help us. We were using ghc-6.4.1 on Linux x86, with gcc 3.3.6. It runs perfectly, and is actually quite fast, when we increase the stack space. :)
import Control.Monad.ST import Data.STRef import Data.Array.ST import Control.Monad.Fix import Control.Monad
while :: STRef s Bool -> ST s () -> ST s () while b c = readSTRef b >>= \v -> when v (c >> while b c)
dot :: STUArray s Int Double -> STUArray s Int Double -> ST s Double dot x y = do let (l,r) = bounds x a <- newSTRef 0.0 e <- newSTRef l b <- newSTRef True while b (do ev <- readSTRef e av <- readSTRef a xe <- readArray x ev ye <- readArray y ev writeSTRef b (ev
main = do let d = runST (do x <- newArray (1, 1000000) 1.0 y <- newArray (1, 1000000) 2.0 dot x y) putStrLn $ show d
Unfortunately, I did not keep every 'while' implementation we tried, just this one:
while b c = fix (\d -> readSTRef b >>= (\v -> if v then c >> d else return ()))
We also changed the 'dot' code to use a 'for' loop instead, using IOUArrays in this case:
for :: Int -> IO () -> IO () for 0 c = return () for n c = c >> for (n-1) c
Needless to say, it did not help. Any hints why the stack overflows would be greatly appreciated. Thanks, Gunnar.

Hello Gunnar, Thursday, April 20, 2006, 4:29:29 PM, you wrote:
a friend and I were recently experimenting with mutable arrays. We tried to implement a simple dot product on STUArrays using a 'while' loop. Unfortunately, every implementation we produced caused a stack overflow.
it seems that you just construct huge unevaluated thunk. making things stricter is a whole art, in this case try the following:
writeSTRef b (ev
writeSTRef b $! (ev for :: Int -> IO () -> IO ()
for 0 c = return ()
for n c = c >> for (n-1) c i recommend you to use your `for` instead of your `while` - it's a much faster
and straightforward
--
Best regards,
Bulat mailto:Bulat.Ziganshin@gmail.com

Hello Bulat, Bulat Ziganshin wrote:
it seems that you just construct huge unevaluated thunk. making things stricter is a whole art, in this case try the following: [...]
Thanks a lot, it works now. I believed that writeSTRef would always evaluate its arguments because ST is strict, but apparently I was mistaken :)
i recommend you to use your `for` instead of your `while` - it's a much faster and straightforward
I agree. Gunnar

Hello Gunnar, Thursday, April 20, 2006, 7:34:33 PM, you wrote:
Thanks a lot, it works now. I believed that writeSTRef would always evaluate its arguments because ST is strict, but apparently I was mistaken :)
strict ST monad means that all operations inside it are performed immediately and not deferred until their side-effect is really required. but when you write something to STRef, this reference just saves closure that will calculate expression. to force evaluation of expression you need also to use '$!' or use unbozed references (that is not yet available, i plan to announce this lib several days later). the fastest way to calculate dot product is: dot :: STUArray s Int Double -> STUArray s Int Double -> ST s Double dot x y = do let (l,r) = bounds x cycle sum i | sum `seq` i>r = return sum cycle sum i = do xi <- readArray x i yi <- readArray y i cycle (sum+xi*yi) (i+1) cycle 0 l -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Hello Bulat, Bulat Ziganshin wrote:
the fastest way to calculate dot product is:
dot :: STUArray s Int Double -> STUArray s Int Double -> ST s Double dot x y = do let (l,r) = bounds x cycle sum i | sum `seq` i>r = return sum cycle sum i = do xi <- readArray x i yi <- readArray y i cycle (sum+xi*yi) (i+1) cycle 0 l
That is a nice implementation. In fact, creating uninitialized arrays with newArray_ and then setting all its elements to some value using a function similar to this one is dramatically faster than creating initialized arrays with newArray. Gunnar.

On 4/20/06, Gunnar Kedenburg
Hello,
a friend and I were recently experimenting with mutable arrays. We tried to implement a simple dot product on STUArrays using a 'while' loop. Unfortunately, every implementation we produced caused a stack overflow. Switching to other implementations of 'while' or to IOUArrays did not help us.
We were using ghc-6.4.1 on Linux x86, with gcc 3.3.6. It runs perfectly, and is actually quite fast, when we increase the stack space. :)
import Control.Monad.ST import Data.STRef import Data.Array.ST import Control.Monad.Fix import Control.Monad
while :: STRef s Bool -> ST s () -> ST s () while b c = readSTRef b >>= \v -> when v (c >> while b c)
dot :: STUArray s Int Double -> STUArray s Int Double -> ST s Double dot x y = do let (l,r) = bounds x a <- newSTRef 0.0 e <- newSTRef l b <- newSTRef True while b (do ev <- readSTRef e av <- readSTRef a xe <- readArray x ev ye <- readArray y ev writeSTRef b (ev
main = do let d = runST (do x <- newArray (1, 1000000) 1.0 y <- newArray (1, 1000000) 2.0 dot x y) putStrLn $ show d
Implementing 'dot' without the 'while' loop and STRefs will make it shorter and faster, btw. -- Friendly, Lemmih
participants (3)
-
Bulat Ziganshin
-
Gunnar Kedenburg
-
Lemmih