;; accumulate.hs — accumulate results into an IORef [Int] (Phase 15 conformance).

(define
  hk-accumulate-source
  "import qualified Data.IORef as IORef\n\npush :: IORef [Int] -> Int -> IO ()\npush r x = IORef.modifyIORef r (\\xs -> x : xs)\n\npushAll :: IORef [Int] -> [Int] -> IO ()\npushAll r [] = return ()\npushAll r (x:xs) = do\n  push r x\n  pushAll r xs\n\nreadReversed :: IORef [Int] -> IO [Int]\nreadReversed r = do\n  xs <- IORef.readIORef r\n  return (reverse xs)\n\ndoubleEach :: IORef [Int] -> [Int] -> IO ()\ndoubleEach r [] = return ()\ndoubleEach r (x:xs) = do\n  push r (x * 2)\n  doubleEach r xs\n\nsumIntoRef :: IORef Int -> [Int] -> IO ()\nsumIntoRef r [] = return ()\nsumIntoRef r (x:xs) = do\n  IORef.modifyIORef r (\\acc -> acc + x)\n  sumIntoRef r xs\n\n")

(hk-test
  "accumulate.hs — push three then read length"
  (hk-deep-force
    (hk-run
      (str
        hk-accumulate-source
        "main = do { r <- IORef.newIORef []; push r 1; push r 2; push r 3; xs <- IORef.readIORef r; return (length xs) }")))
  (list "IO" 3))

(hk-test
  "accumulate.hs — pushAll preserves reverse order"
  (hk-deep-force
    (hk-run
      (str
        hk-accumulate-source
        "main = do { r <- IORef.newIORef []; pushAll r [1,2,3,4]; xs <- IORef.readIORef r; return xs }")))
  (list
    "IO"
    (list ":" 4 (list ":" 3 (list ":" 2 (list ":" 1 (list "[]")))))))

(hk-test
  "accumulate.hs — readReversed gives original order"
  (hk-deep-force
    (hk-run
      (str
        hk-accumulate-source
        "main = do { r <- IORef.newIORef []; pushAll r [10,20,30]; readReversed r }")))
  (list "IO" (list ":" 10 (list ":" 20 (list ":" 30 (list "[]"))))))

(hk-test
  "accumulate.hs — doubleEach maps then accumulates"
  (hk-deep-force
    (hk-run
      (str
        hk-accumulate-source
        "main = do { r <- IORef.newIORef []; doubleEach r [1,2,3]; readReversed r }")))
  (list "IO" (list ":" 2 (list ":" 4 (list ":" 6 (list "[]"))))))

(hk-test
  "accumulate.hs — sum into Int IORef"
  (hk-deep-force
    (hk-run
      (str
        hk-accumulate-source
        "main = do { r <- IORef.newIORef 0; sumIntoRef r [1,2,3,4,5]; v <- IORef.readIORef r; return v }")))
  (list "IO" 15))

(hk-test
  "accumulate.hs — empty list leaves ref untouched"
  (hk-deep-force
    (hk-run
      (str
        hk-accumulate-source
        "main = do { r <- IORef.newIORef [99]; pushAll r []; xs <- IORef.readIORef r; return xs }")))
  (list "IO" (list ":" 99 (list "[]"))))

(hk-test
  "accumulate.hs — pushAll then sumIntoRef on the same input"
  (hk-deep-force
    (hk-run
      (str
        hk-accumulate-source
        "main = do { r <- IORef.newIORef 0; sumIntoRef r [10,20,30,40]; v <- IORef.readIORef r; return v }")))
  (list "IO" 100))

(hk-test
  "accumulate.hs — accumulate results from a recursive helper"
  (hk-deep-force
    (hk-run
      (str
        hk-accumulate-source
        "squaresUpTo r 0 = return ()\nsquaresUpTo r n = do { push r (n * n); squaresUpTo r (n - 1) }\nmain = do { r <- IORef.newIORef []; squaresUpTo r 4; readReversed r }")))
  (list
    "IO"
    (list ":" 16 (list ":" 9 (list ":" 4 (list ":" 1 (list "[]")))))))
