;; counter.hs — IORef-backed mutable counter (Phase 15 conformance).

(define
  hk-counter-source
  "import qualified Data.IORef as IORef\n\ncount :: IORef Int -> Int -> IO ()\ncount r 0 = return ()\ncount r n = do\n  IORef.modifyIORef r (\\x -> x + 1)\n  count r (n - 1)\n\ncountBy :: IORef Int -> Int -> Int -> IO ()\ncountBy r step 0 = return ()\ncountBy r step n = do\n  IORef.modifyIORef r (\\x -> x + step)\n  countBy r step (n - 1)\n\nnewCounter :: Int -> IO (IORef Int)\nnewCounter v = IORef.newIORef v\n\nbumpAndRead :: IORef Int -> IO Int\nbumpAndRead r = do\n  IORef.modifyIORef r (\\x -> x + 1)\n  IORef.readIORef r\n\n")

(hk-test
  "counter.hs — start at 0, count 5 ⇒ 5"
  (hk-deep-force
    (hk-run
      (str
        hk-counter-source
        "main = do { r <- newCounter 0; count r 5; v <- IORef.readIORef r; return v }")))
  (list "IO" 5))

(hk-test
  "counter.hs — start at 100, count 10 ⇒ 110"
  (hk-deep-force
    (hk-run
      (str
        hk-counter-source
        "main = do { r <- newCounter 100; count r 10; v <- IORef.readIORef r; return v }")))
  (list "IO" 110))

(hk-test
  "counter.hs — countBy step 5, n 4 ⇒ 20"
  (hk-deep-force
    (hk-run
      (str
        hk-counter-source
        "main = do { r <- newCounter 0; countBy r 5 4; v <- IORef.readIORef r; return v }")))
  (list "IO" 20))

(hk-test
  "counter.hs — bumpAndRead returns updated value"
  (hk-deep-force
    (hk-run
      (str hk-counter-source "main = do { r <- newCounter 41; bumpAndRead r }")))
  (list "IO" 42))

(hk-test
  "counter.hs — count then countBy compose"
  (hk-deep-force
    (hk-run
      (str
        hk-counter-source
        "main = do { r <- newCounter 0; count r 3; countBy r 10 2; v <- IORef.readIORef r; return v }")))
  (list "IO" 23))

(hk-test
  "counter.hs — two independent counters"
  (hk-deep-force
    (hk-run
      (str
        hk-counter-source
        "main = do { a <- newCounter 0; b <- newCounter 0; count a 7; countBy b 100 2; va <- IORef.readIORef a; vb <- IORef.readIORef b; return (va + vb) }")))
  (list "IO" 207))

(hk-test
  "counter.hs — modifyIORef' (strict) variant"
  (hk-deep-force
    (hk-run
      (str
        hk-counter-source
        "tick r 0 = return ()\ntick r n = do { IORef.modifyIORef' r (\\x -> x + 1); tick r (n - 1) }\nmain = do { r <- newCounter 0; tick r 50; v <- IORef.readIORef r; return v }")))
  (list "IO" 50))
