;; do-notation + stub IO monad. Desugaring is per Haskell 98 §3.14: ;; do { e ; ss } = e >> do { ss } ;; do { p <- e ; ss } = e >>= \p -> do { ss } ;; do { let ds ; ss } = let ds in do { ss } ;; do { e } = e ;; The IO type is just `("IO" payload)` for now — no real side ;; effects yet. `return`, `>>=`, `>>` are built-ins. (define hk-prog-val (fn (src name) (hk-deep-force (get (hk-eval-program (hk-core src)) name)))) ;; ── Single-statement do ── (hk-test "do with a single expression" (hk-eval-expr-source "do { return 5 }") (list "IO" 5)) (hk-test "return wraps any expression" (hk-eval-expr-source "return (1 + 2 * 3)") (list "IO" 7)) ;; ── Bind threads results ── (hk-test "single bind" (hk-eval-expr-source "do { x <- return 5 ; return (x + 1) }") (list "IO" 6)) (hk-test "two binds" (hk-eval-expr-source "do\n x <- return 5\n y <- return 7\n return (x + y)") (list "IO" 12)) (hk-test "three binds — accumulating" (hk-eval-expr-source "do\n a <- return 1\n b <- return 2\n c <- return 3\n return (a + b + c)") (list "IO" 6)) ;; ── Mixing >> and >>= ── (hk-test ">> sequencing — last wins" (hk-eval-expr-source "do\n return 1\n return 2\n return 3") (list "IO" 3)) (hk-test ">> then >>= — last bind wins" (hk-eval-expr-source "do\n return 99\n x <- return 5\n return x") (list "IO" 5)) ;; ── do-let ── (hk-test "do-let single binding" (hk-eval-expr-source "do\n let x = 3\n return (x * 2)") (list "IO" 6)) (hk-test "do-let multi-bind, used after" (hk-eval-expr-source "do\n let x = 4\n y = 5\n return (x * y)") (list "IO" 20)) (hk-test "do-let interleaved with bind" (hk-eval-expr-source "do\n x <- return 10\n let y = x + 1\n return (x * y)") (list "IO" 110)) ;; ── Bind + pattern ── (hk-test "bind to constructor pattern" (hk-eval-expr-source "do\n Just x <- return (Just 7)\n return (x + 100)") (list "IO" 107)) (hk-test "bind to tuple pattern" (hk-eval-expr-source "do\n (a, b) <- return (3, 4)\n return (a * b)") (list "IO" 12)) ;; ── User-defined IO functions ── (hk-test "do inside top-level fun" (hk-prog-val "addM x y = do\n a <- return x\n b <- return y\n return (a + b)\nresult = addM 5 6" "result") (list "IO" 11)) (hk-test "nested do" (hk-eval-expr-source "do\n x <- do { y <- return 3 ; return (y + 1) }\n return (x * 2)") (list "IO" 8)) ;; ── (>>=) and (>>) used directly as functions ── (hk-test ">>= used directly" (hk-eval-expr-source "(return 4) >>= (\\x -> return (x + 100))") (list "IO" 104)) (hk-test ">> used directly" (hk-eval-expr-source "(return 1) >> (return 2)") (list "IO" 2)) {:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}