;; either.hs — Either ADT operations via pattern matching.

(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-either-src
  "safeDiv _ 0 = Left \"divide by zero\"\nsafeDiv x y = Right (x `div` y)\n\nfromRight _ (Right x) = x\nfromRight def (Left _) = def\n\nfromLeft (Left x) _ = x\nfromLeft _ def = def\n\nisRight (Right _) = True\nisRight (Left _) = False\n\nisLeft (Left _) = True\nisLeft (Right _) = False\n\nmapRight _ (Left e) = Left e\nmapRight f (Right x) = Right (f x)\n\ndouble x = x * 2\n")

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

(hk-test
  "safeDiv 7 0 = Left msg"
  (hk-prog-val (str hk-either-src "r = safeDiv 7 0\n") "r")
  (list "Left" "divide by zero"))

(hk-test
  "fromRight 0 (Right 42) = 42"
  (hk-prog-val (str hk-either-src "r = fromRight 0 (Right 42)\n") "r")
  42)

(hk-test
  "fromRight 0 (Left msg) = 0"
  (hk-prog-val (str hk-either-src "r = fromRight 0 (Left \"err\")\n") "r")
  0)

(hk-test
  "isRight (Right 1) = True"
  (hk-prog-val (str hk-either-src "r = isRight (Right 1)\n") "r")
  (list "True"))

(hk-test
  "isRight (Left x) = False"
  (hk-prog-val (str hk-either-src "r = isRight (Left \"x\")\n") "r")
  (list "False"))

(hk-test
  "isLeft (Left x) = True"
  (hk-prog-val (str hk-either-src "r = isLeft (Left \"x\")\n") "r")
  (list "True"))

(hk-test
  "isLeft (Right x) = False"
  (hk-prog-val (str hk-either-src "r = isLeft (Right 1)\n") "r")
  (list "False"))

(hk-test
  "mapRight double (Right 5) = Right 10"
  (hk-prog-val (str hk-either-src "r = mapRight double (Right 5)\n") "r")
  (list "Right" 10))

(hk-test
  "mapRight double (Left e) = Left e"
  (hk-prog-val (str hk-either-src "r = mapRight double (Left \"err\")\n") "r")
  (list "Left" "err"))

(hk-test
  "chain safeDiv results"
  (hk-prog-val (str hk-either-src "r = fromRight (-1) (safeDiv 20 4)\n") "r")
  5)

(hk-test
  "chain safeDiv error"
  (hk-prog-val (str hk-either-src "r = fromRight (-1) (safeDiv 20 0)\n") "r")
  -1)

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