;; Guards and where-clauses — on fun-clauses, case alts, and ;; let-bindings (which now also accept funclause-style LHS like ;; `let f x = e` or `let f x | g = e | g = e`). (define hk-prog (fn (&rest decls) (list :program decls))) ;; ── Guarded fun-clauses ── (hk-test "simple guards (two branches)" (hk-parse-top "abs x | x < 0 = - x\n | otherwise = x") (hk-prog (list :fun-clause "abs" (list (list :p-var "x")) (list :guarded (list (list :guard (list :op "<" (list :var "x") (list :int 0)) (list :neg (list :var "x"))) (list :guard (list :var "otherwise") (list :var "x"))))))) (hk-test "three-way guard" (hk-parse-top "sign n | n > 0 = 1\n | n < 0 = -1\n | otherwise = 0") (hk-prog (list :fun-clause "sign" (list (list :p-var "n")) (list :guarded (list (list :guard (list :op ">" (list :var "n") (list :int 0)) (list :int 1)) (list :guard (list :op "<" (list :var "n") (list :int 0)) (list :neg (list :int 1))) (list :guard (list :var "otherwise") (list :int 0))))))) (hk-test "mixed: one eq clause plus one guarded clause" (hk-parse-top "sign 0 = 0\nsign n | n > 0 = 1\n | otherwise = -1") (hk-prog (list :fun-clause "sign" (list (list :p-int 0)) (list :int 0)) (list :fun-clause "sign" (list (list :p-var "n")) (list :guarded (list (list :guard (list :op ">" (list :var "n") (list :int 0)) (list :int 1)) (list :guard (list :var "otherwise") (list :neg (list :int 1)))))))) ;; ── where on fun-clauses ── (hk-test "where with one binding" (hk-parse-top "f x = y + y\n where y = x + 1") (hk-prog (list :fun-clause "f" (list (list :p-var "x")) (list :where (list :op "+" (list :var "y") (list :var "y")) (list (list :fun-clause "y" (list) (list :op "+" (list :var "x") (list :int 1)))))))) (hk-test "where with multiple bindings" (hk-parse-top "f x = y * z\n where y = x + 1\n z = x - 1") (hk-prog (list :fun-clause "f" (list (list :p-var "x")) (list :where (list :op "*" (list :var "y") (list :var "z")) (list (list :fun-clause "y" (list) (list :op "+" (list :var "x") (list :int 1))) (list :fun-clause "z" (list) (list :op "-" (list :var "x") (list :int 1)))))))) (hk-test "guards + where" (hk-parse-top "f x | x > 0 = y\n | otherwise = 0\n where y = 99") (hk-prog (list :fun-clause "f" (list (list :p-var "x")) (list :where (list :guarded (list (list :guard (list :op ">" (list :var "x") (list :int 0)) (list :var "y")) (list :guard (list :var "otherwise") (list :int 0)))) (list (list :fun-clause "y" (list) (list :int 99))))))) ;; ── Guards in case alts ── (hk-test "case alt with guards" (hk-parse "case x of\n Just y | y > 0 -> y\n | otherwise -> 0\n Nothing -> 0") (list :case (list :var "x") (list (list :alt (list :p-con "Just" (list (list :p-var "y"))) (list :guarded (list (list :guard (list :op ">" (list :var "y") (list :int 0)) (list :var "y")) (list :guard (list :var "otherwise") (list :int 0))))) (list :alt (list :p-con "Nothing" (list)) (list :int 0))))) (hk-test "case alt with where" (hk-parse "case x of\n Just y -> y + z where z = 5\n Nothing -> 0") (list :case (list :var "x") (list (list :alt (list :p-con "Just" (list (list :p-var "y"))) (list :where (list :op "+" (list :var "y") (list :var "z")) (list (list :fun-clause "z" (list) (list :int 5))))) (list :alt (list :p-con "Nothing" (list)) (list :int 0))))) ;; ── let-bindings: funclause form, guards, where ── (hk-test "let with funclause shorthand" (hk-parse "let f x = x + 1 in f 5") (list :let (list (list :fun-clause "f" (list (list :p-var "x")) (list :op "+" (list :var "x") (list :int 1)))) (list :app (list :var "f") (list :int 5)))) (hk-test "let with guards" (hk-parse "let f x | x > 0 = x\n | otherwise = 0\nin f 3") (list :let (list (list :fun-clause "f" (list (list :p-var "x")) (list :guarded (list (list :guard (list :op ">" (list :var "x") (list :int 0)) (list :var "x")) (list :guard (list :var "otherwise") (list :int 0)))))) (list :app (list :var "f") (list :int 3)))) (hk-test "let funclause + where" (hk-parse "let f x = y where y = x + 1\nin f 7") (list :let (list (list :fun-clause "f" (list (list :p-var "x")) (list :where (list :var "y") (list (list :fun-clause "y" (list) (list :op "+" (list :var "x") (list :int 1))))))) (list :app (list :var "f") (list :int 7)))) ;; ── Nested: where inside where (via recursive hk-parse-decl) ── (hk-test "where block can contain a type signature" (hk-parse-top "f x = y\n where y :: Int\n y = x") (hk-prog (list :fun-clause "f" (list (list :p-var "x")) (list :where (list :var "y") (list (list :type-sig (list "y") (list :t-con "Int")) (list :fun-clause "y" (list) (list :var "x"))))))) {:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}