;; safediv.hs — safe division using catch (Phase 16 conformance).

(define
  hk-safediv-source
  "safeDiv :: Int -> Int -> IO Int
safeDiv _ 0 = throwIO (SomeException \"division by zero\")
safeDiv x y = return (x `div` y)

guarded :: Int -> Int -> IO Int
guarded x y = catch (safeDiv x y) (\\(SomeException _) -> return 0)

reason :: Int -> Int -> IO String
reason x y = catch (safeDiv x y `seq` return \"ok\")
  (\\(SomeException m) -> return m)

bothBranches :: Int -> Int -> IO Int
bothBranches x y = do
  v <- catch (safeDiv x y) (\\(SomeException _) -> return (-1))
  return (v + 100)

")

(hk-test
  "safediv.hs — divide by non-zero"
  (hk-deep-force
    (hk-run
      (str hk-safediv-source "main = guarded 10 2")))
  (list "IO" 5))

(hk-test
  "safediv.hs — divide by zero returns 0"
  (hk-deep-force
    (hk-run
      (str hk-safediv-source "main = guarded 10 0")))
  (list "IO" 0))

(hk-test
  "safediv.hs — divide by zero — reason captured"
  (hk-deep-force
    (hk-run
      (str hk-safediv-source "main = catch (safeDiv 1 0) (\\(SomeException m) -> return 0) >> reason 1 0")))
  (list "IO" "division by zero"))

(hk-test
  "safediv.hs — bothBranches success path"
  (hk-deep-force
    (hk-run
      (str hk-safediv-source "main = bothBranches 8 2")))
  (list "IO" 104))

(hk-test
  "safediv.hs — bothBranches failure path"
  (hk-deep-force
    (hk-run
      (str hk-safediv-source "main = bothBranches 8 0")))
  (list "IO" 99))

(hk-test
  "safediv.hs — chained safeDiv with catch"
  (hk-deep-force
    (hk-run
      (str hk-safediv-source
        "main = do { a <- guarded 20 4; b <- guarded 7 0; return (a + b) }")))
  (list "IO" 5))

(hk-test
  "safediv.hs — try then bind through Either"
  (hk-deep-force
    (hk-run
      (str hk-safediv-source
        "main = do { r <- try (safeDiv 1 0); case r of { Right v -> return v; Left (SomeException m) -> return 999 } }")))
  (list "IO" 999))

(hk-test
  "safediv.hs — handle (flip catch)"
  (hk-deep-force
    (hk-run
      (str hk-safediv-source
        "main = handle (\\(SomeException _) -> return 0) (safeDiv 5 0)")))
  (list "IO" 0))
