def test_typecheck_builtins(self): """Make sure builtin types typecheck correctly""" # 1 :: int self.unified(typeof(1), TypeOperator(int, [])) # "a" :: str self.unified(typeof("a"), TypeOperator(str, [])) # Nothing :: Maybe a self.unified(typeof(Nothing), TypeOperator(Maybe, [TypeVariable()])) # Just(1) :: Maybe int self.unified(typeof(Just(1)), TypeOperator(Maybe, [TypeOperator(int, [])])) # Just(Just(Nothing)) :: Maybe (Maybe (Maybe a)) self.unified( typeof(Just(Just(Nothing))), TypeOperator( Maybe, [TypeOperator(Maybe, [TypeOperator(Maybe, [TypeVariable()])]) ])) # Right("error") :: Either a str self.unified( typeof(Right("error")), TypeOperator( Either, [TypeVariable(), TypeOperator(str, [])])) # Left(2.0) :: Either float a self.unified( typeof(Left(2.0)), TypeOperator(Either, [TypeOperator(float, []), TypeVariable()]))
def test_build_sig_item(self): """Test type signature building internals - make sure that types are translated in a reasonable way""" class example: pass # type variables self.assertTrue(isinstance(build_sig_arg("a", {}, {}), TypeVariable)) self.assertTrue(isinstance(build_sig_arg("abc", {}, {}), TypeVariable)) # builtin/non-ADT types self.unified(build_sig_arg(str, {}, {}), TypeOperator(str, [])) self.unified(build_sig_arg(int, {}, {}), TypeOperator(int, [])) self.unified(build_sig_arg(float, {}, {}), TypeOperator(float, [])) self.unified(build_sig_arg(list, {}, {}), TypeOperator(list, [])) self.unified(build_sig_arg(set, {}, {}), TypeOperator(set, [])) self.unified(build_sig_arg(example, {}, {}), TypeOperator(example, [])) # unit type (None) self.unified(build_sig_arg(None, {}, {}), TypeOperator(None, [])) # tuple self.unified(build_sig_arg((int, int), {}, {}), Tuple([TypeOperator(int, []), TypeOperator(int, [])])) self.unified( build_sig_arg((None, (None, int)), {}, {}), Tuple([ TypeOperator(None, []), Tuple([TypeOperator(None, []), TypeOperator(int, [])]) ])) a = TypeVariable() self.unified(build_sig_arg(("a", "a", "a"), {}, {}), Tuple([a, a, a])) # list self.unified(typeof(L[[]]), build_sig_arg(["a"], {}, {})) self.unified(typeof(L[1, 1]), build_sig_arg([int], {}, {})) self.unified(typeof(L[[L[1, 1]]]), build_sig_arg([[int]], {}, {})) # adts self.unified(typeof(Nothing), build_sig_arg(t(Maybe, "a"), {}, {})) self.unified(typeof(Just(1)), build_sig_arg(t(Maybe, int), {}, {})) self.unified(typeof(Just(Just(Nothing))), build_sig_arg(t(Maybe, t(Maybe, t(Maybe, "a"))), {}, {})) self.unified(typeof(Right("error")), build_sig_arg(t(Either, str, "a"), {}, {})) self.unified(typeof(Left(2.0)), build_sig_arg(t(Either, "a", int), {}, {})) self.unified(typeof(Just(__ + 1)), build_sig_arg(t(Maybe, "a"), {}, {})) self.unified(typeof(Just(__ + 1)), build_sig_arg(t(Maybe, (H / "a" >> "b")), {}, {}))
def test_show(self): from hask3.Prelude import show self.assertEqual("Left(1)", str(Left(1))) self.assertEqual("Left('1')", str(Left("1"))) self.assertEqual("Right(1)", str(Right(1))) self.assertEqual("Right('1')", str(Right("1"))) self.assertEqual("Right(Left('1'))", str(Right(Left("1")))) self.assertEqual("Left(1)", show(Left(1))) self.assertEqual("Left('1')", show(Left("1"))) self.assertEqual("Right(1)", show(Right(1))) self.assertEqual("Right('1')", show(Right("1"))) self.assertEqual("Right(Left('1'))", show(Right(Left("1"))))
def test_decorators(self): def eat_cheese(cheese): if cheese <= 0: raise ValueError("Out of cheese error") return cheese - 1 maybe_eat = in_maybe(eat_cheese) self.assertEqual(maybe_eat(1), Just(0)) self.assertEqual(maybe_eat(0), Nothing) self.assertEqual(Just(6), Just(7) >> maybe_eat) self.assertEqual(Just(7), Just(10) >> maybe_eat >> maybe_eat >> maybe_eat) self.assertEqual(Nothing, Just(1) >> maybe_eat >> maybe_eat >> maybe_eat) either_eat = in_either(eat_cheese) self.assertEqual(either_eat(10), Right(9)) self.assertTrue(isinstance(either_eat(0)[0], ValueError))
def test_match(self): match_only = lambda v, p: pattern_match(v, p)[0] pb = PatternMatchBind # literal matches self.assertTrue(match_only(1, 1)) self.assertTrue(match_only((1, "a"), (1, "a"))) self.assertTrue(match_only(Nothing, Nothing)) self.assertTrue(match_only(Just(1), Just(1))) self.assertFalse(match_only(2, 1)) self.assertFalse(match_only(("a", 1), (1, "a"))) self.assertFalse(match_only(("a", "b"), ["a", "b"])) self.assertFalse(match_only(Nothing, Just(Nothing))) self.assertFalse(match_only(Just(2), Just(1))) self.assertFalse(match_only(Right(2), Just(2))) self.assertFalse(match_only(Right(2), Left(2))) # matches with wildcard (i.e, discarded variable bind) self.assertTrue(match_only(1, pb("_"))) self.assertTrue(match_only(Nothing, pb("_"))) self.assertTrue(match_only(Just("whatever"), Just(pb("_")))) self.assertTrue(match_only(Right(Just(5)), Right(Just(pb("_"))))) self.assertTrue(match_only(("a", "b", "c"), ("a", pb("_"), "c"))) self.assertFalse(match_only(("a", "b", "c"), ("1", pb("_"), "c"))) self.assertFalse(match_only(("a", "b", "d"), ("a", pb("_"), "c"))) # matches with variable binding self.assertEqual((True, {"a": 1}), pattern_match(1, pb("a"))) self.assertEqual((True, { "a": 1, "b": 2 }), pattern_match((1, 2), (pb("a"), pb("b")))) self.assertEqual((True, { "a": 8 }), pattern_match(Just(8), Just(pb("a")))) self.assertEqual((True, { "a": "a" }), pattern_match(Right(Just("a")), Right(Just(pb("a"))))) self.assertEqual((False, { "a": 1 }), pattern_match((2, 1), (3, pb("a")))) self.assertEqual((True, { "a": 1, "b": 2, "_": "a" }), pattern_match((1, "a", 2), (pb("a"), pb("_"), pb("b")))) with self.assertRaises(SyntaxError): pattern_match((1, 2), (pb("c"), pb("a")), {"c": 1}) with self.assertRaises(SyntaxError): pattern_match((1, 2), (pb("c"), pb("a")), {"a": 1})
def test_functor(self): from hask3.Prelude import id, fmap, const self.assertEqual(Left(7), fmap(__+1, Left(7))) self.assertEqual(Left("a"), fmap(__+1, Left("a"))) self.assertEqual(Right(8), fmap(__+1, Right(7))) with self.assertRaises(TypeError): fmap(__+1, Right("a")) self.assertEqual(Right(Left(1)), fmap(const(Left(1)), Right("a"))) self.assertEqual(Left("a"), fmap(const(Left(1)), Left("a"))) f = (lambda x: x + "!") ** (H/ str >> str) g = (lambda x: x + "?") ** (H/ str >> str) self.assertEqual(Right("b?!"), (f * g) * Right("b")) self.assertEqual(Right("b?!"), f * g * Right("b")) self.assertEqual(Left("b"), (f * g) * Left("b")) self.assertEqual(Left("b"), f * g * Left("b")) # functor laws self.assertEqual(Left(7), fmap(id, Left(7))) self.assertEqual(Right(7), fmap(id, Right(7))) self.assertEqual(Right("a?!"), fmap(f * g, Right("a"))) self.assertEqual(Left("a"), fmap(f * g, Left("a"))) self.assertEqual(Right("a?!"), fmap(f, fmap(g, Right("a")))) self.assertEqual(Left("a"), fmap(f, fmap(g, Left("a"))))
def test_ord(self): self.assertTrue(Left(20) < Right(0)) self.assertTrue(Left(20) < Right("a")) self.assertTrue(Left(2) < Left(3)) self.assertTrue(Right(2) < Right(3)) self.assertTrue(Left(20) <= Right(0)) self.assertTrue(Left(20) <= Right("a")) self.assertTrue(Left(2) <= Left(3)) self.assertTrue(Right(2) <= Right(3)) self.assertFalse(Right(0) < Left(20)) self.assertFalse(Right("a") < Left(20)) self.assertFalse(Left(3) < Left(2)) self.assertFalse(Right(3) < Right(2)) self.assertFalse(Right(2) <= Left(20)) self.assertFalse(Right("a") <= Left(20)) self.assertFalse(Left(3) <= Left(2)) self.assertFalse(Right(3) <= Right(2)) self.assertTrue(Right(0) > Left(20)) self.assertTrue(Right("a") > Left(20)) self.assertTrue(Left(3) > Left(2)) self.assertTrue(Right(3) > Right(2)) self.assertTrue(Right(2) >= Left(20)) self.assertTrue(Right("a") >= Left(20)) self.assertTrue(Left(3) >= Left(2)) self.assertTrue(Right(3) >= Right(2)) self.assertFalse(Left(20) > Right(0)) self.assertFalse(Left(20) > Right("a")) self.assertFalse(Left(2) > Left(3)) self.assertFalse(Right(2) > Right(3)) self.assertFalse(Left(20) >= Right(0)) self.assertFalse(Left(20) >= Right("a")) self.assertFalse(Left(2) >= Left(3)) self.assertFalse(Right(2) >= Right(3)) self.assertFalse(Right(3) > Right(3)) self.assertFalse(Left(3) > Left(3)) self.assertFalse(Right(3) < Right(3)) self.assertFalse(Left(3) < Left(3)) self.assertTrue(Left(2.0) <= Left(2.0)) self.assertTrue(Right(2) <= Right(2)) self.assertTrue(Left(2.0) >= Left(2.0)) self.assertTrue(Right(2) >= Right(2))
def test_eq(self): self.assertTrue(Left(1) == Left(1)) self.assertTrue(Right(1) == Right(1)) self.assertFalse(Left(1) == Left(2)) self.assertFalse(Right(1) == Right(2)) self.assertFalse(Left(1) == Right(1)) self.assertFalse(Left("a") == Right(1)) self.assertFalse(Left(1) != Left(1)) self.assertFalse(Right(1) != Right(1)) self.assertTrue(Left(1) != Left(2)) self.assertTrue(Right(1) != Right(2)) self.assertTrue(Left(1) != Right(1)) self.assertTrue(Left("a") != Right(1))
def test_functions(self): from hask3.Data.Either import either from hask3.Data.Either import isRight from hask3.Data.Either import isLeft from hask3.Data.Either import lefts from hask3.Data.Either import rights from hask3.Data.Either import partitionEithers f = (lambda x: x + " world") ** (H/ str >> str) g = (lambda x: str(x * 10)) ** (H/ int >> str) self.assertEqual('20', either(f, g, Right(2))) self.assertEqual("hello world", either(f, g, Left("hello"))) self.assertTrue(isLeft(Left(1))) self.assertTrue(isRight(Right("a"))) self.assertFalse(isLeft(Right("a"))) self.assertFalse(isRight(Left(1))) self.assertEqual(L[1, 3], rights(L[Right(1), Left(2), Right(3), Left(4)])) self.assertEqual(L[[]], rights(L[[]])) self.assertEqual(L[2, 4], lefts(L[Right(1), Left(2), Right(3), Left(4)])) self.assertEqual(L[[]], lefts(L[[]])) self.assertEqual((L[2, 4], L[1, 3]), partitionEithers(L[Right(1), Left(2), Right(3), Left(4)])) self.assertEqual((L[2, 4], L[[]]), partitionEithers(L[Left(2), Left(4)])) self.assertEqual((L[[]], L[1, 3]), partitionEithers(L[Right(1), Right(3)])) self.assertEqual((L[[]], L[[]]), partitionEithers(L[[]]))
def sub_whole(x, y): return Right(x-y) if (x-y) >= 0 else Left("err")
def test_monad(self): from hask3.Prelude import flip from hask3.Control.Monad import bind, join @sig(H/ int >> int >> t(Either, str, int)) def sub_whole(x, y): return Right(x-y) if (x-y) >= 0 else Left("err") sub = flip(sub_whole) self.assertEqual(Right(2), Right(4) >> sub(2)) self.assertEqual(Right(0), Right(4) >> sub(2) >> sub(2)) self.assertEqual(Left("err"), Right(4) >> sub(10)) self.assertEqual(Left("0"), Left("0") >> sub_whole(1)) # monad laws sub_composed = (lambda x: sub_whole(4, x) >> sub(2)) ** \ (H/ int >> t(Either, "a", int)) self.assertEqual(Right(7), Right(7) >> Right) self.assertEqual(Left(7), Left(7) >> Right) self.assertEqual(Right(1), (Right(5) >> sub(1)) >> sub(3)) self.assertEqual(Left("e"), (Left("e") >> sub(1)) >> sub(3)) self.assertEqual(Left("err"), (Right(5) >> sub(10)) >> sub(3)) self.assertEqual(Right(0), Right(2) >> sub_composed) self.assertEqual(Left("e"), Left("e") >> sub_composed) self.assertEqual(Right(2), bind(Right(4), sub(2))) self.assertEqual(join(Right(Right(1))), Right(1)) self.assertEqual(join(Right(Left(1))), Left(1))