;; maybe.hs — safe operations returning Maybe values.

(define
  hk-prog-val
  (fn
    (src name)
    (hk-deep-force (get (hk-eval-program (hk-core src)) name))))

(define
  hk-as-list
  (fn
    (xs)
    (cond
      ((and (list? xs) (= (first xs) "[]")) (list))
      ((and (list? xs) (= (first xs) ":"))
        (cons (nth xs 1) (hk-as-list (nth xs 2))))
      (:else xs))))

(define
  hk-maybe-src
  "safeDiv _ 0 = Nothing\nsafeDiv x y = Just (x `div` y)\n\nsafeHead [] = Nothing\nsafeHead (x:_) = Just x\n\nfromMaybeZero Nothing = 0\nfromMaybeZero (Just x) = x\n\nmapMaybe _ Nothing = Nothing\nmapMaybe f (Just x) = Just (f x)\n\ndouble x = x * 2\n")

(hk-test
  "safeDiv 10 2 = Just 5"
  (hk-prog-val (str hk-maybe-src "r = safeDiv 10 2\n") "r")
  (list "Just" 5))

(hk-test
  "safeDiv 7 0 = Nothing"
  (hk-prog-val (str hk-maybe-src "r = safeDiv 7 0\n") "r")
  (list "Nothing"))

(hk-test
  "safeHead [1,2,3] = Just 1"
  (hk-prog-val (str hk-maybe-src "r = safeHead [1,2,3]\n") "r")
  (list "Just" 1))

(hk-test
  "safeHead [] = Nothing"
  (hk-prog-val (str hk-maybe-src "r = safeHead []\n") "r")
  (list "Nothing"))

(hk-test
  "fromMaybeZero Nothing = 0"
  (hk-prog-val (str hk-maybe-src "r = fromMaybeZero Nothing\n") "r")
  0)

(hk-test
  "fromMaybeZero (Just 42) = 42"
  (hk-prog-val (str hk-maybe-src "r = fromMaybeZero (Just 42)\n") "r")
  42)

(hk-test
  "mapMaybe double Nothing = Nothing"
  (hk-prog-val (str hk-maybe-src "r = mapMaybe double Nothing\n") "r")
  (list "Nothing"))

(hk-test
  "mapMaybe double (Just 5) = Just 10"
  (hk-prog-val (str hk-maybe-src "r = mapMaybe double (Just 5)\n") "r")
  (list "Just" 10))

(hk-test
  "chain: fromMaybeZero (safeDiv 10 2) = 5"
  (hk-prog-val (str hk-maybe-src "r = fromMaybeZero (safeDiv 10 2)\n") "r")
  5)

(hk-test
  "chain: fromMaybeZero (safeDiv 10 0) = 0"
  (hk-prog-val (str hk-maybe-src "r = fromMaybeZero (safeDiv 10 0)\n") "r")
  0)

(hk-test
  "safeDiv 100 5 = Just 20"
  (hk-prog-val (str hk-maybe-src "r = safeDiv 100 5\n") "r")
  (list "Just" 20))

(hk-test
  "mapMaybe double (safeDiv 6 2) = Just 6"
  (hk-prog-val (str hk-maybe-src "r = mapMaybe double (safeDiv 6 2)\n") "r")
  (list "Just" 6))

{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}
