Пример #1
0
    def test_match(self):
        @sig(H/ int >> int)
        def fib(x):
            return ~(caseof(x)
                        | m(0)   >> 1
                        | m(1)   >> 1
                        | m(m.n) >> fib(p.n - 2) + fib(p.n - 1)
                    )

        self.assertEqual(1, fib(0))
        self.assertEqual(1, fib(1))
        self.assertEqual(13, fib(6))

        def default_to_zero(x):
            return ~(caseof(x)
                        | m(Just(m.x)) >> p.x
                        | m(Nothing)   >> 0)

        self.assertEqual(default_to_zero(Just(27)), 27)
        self.assertEqual(default_to_zero(Nothing), 0)
        self.assertEqual(Just(20.0)[0], 20.0)
        self.assertEqual(Left("words words words words")[0],
                         "words words words words")
        with self.assertRaises(IndexError):
            Nothing[0]
Пример #2
0
    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()]))
Пример #3
0
    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")), {}, {}))
Пример #4
0
 def test_show(self):
     from hask3.Prelude import show
     self.assertEqual("Just(3)", str(Just(3)))
     self.assertEqual("Just(3)", show(Just(3)))
     self.assertEqual("Just('a')", str(Just("a")))
     self.assertEqual("Just('a')", show(Just("a")))
     self.assertEqual("Just(Just(3))", str(Just(Just(3))))
     self.assertEqual("Just(Just(3))", show(Just(Just(3))))
     self.assertEqual("Nothing", str(Nothing))
     self.assertEqual("Nothing", show(Nothing))
Пример #5
0
    def test_typeclasses(self):
        from hask3.Prelude import fmap
        M, N, J = data.M("a") == d.N | d.J("a") & deriving(Show, Eq, Ord)

        def maybe_fmap(fn, maybe_value):
            return ~(caseof(maybe_value)
                        | m(N)      >> N
                        | m(J(m.x)) >> J(fn(p.x))
                    )

        instance(Functor, M).where(
            fmap = maybe_fmap
        )

        times2 = (lambda x: x * 2) ** (H/ int >> int)
        toFloat = float ** (H/ int >> float)

        self.assertEqual(fmap(toFloat, J(10)), J(10.0))
        self.assertEqual(fmap(toFloat, fmap(times2, J(25))), J(50.0))
        self.assertEqual((toFloat * times2) * J(25), J(50.0))
        self.assertEqual((toFloat * times2) * N, N)

        instance(Applicative, M).where(
            pure = J
        )

        instance(Monad, M).where(
            bind = lambda x, f: ~(caseof(x)
                                    | m(J(m.a)) >> f(p.a)
                                    | m(N)   >> N)
        )

        @sig(H/ int >> int >> t(M, int))
        def safe_div(x, y):
            return N if y == 0 else J(x//y)

        from hask3.Prelude import flip
        divBy = flip(safe_div)
        self.assertEqual(J(9) >> divBy(3), J(3))

        self.assertEqual(Just(12) >> divBy(2) >> divBy(2) >> divBy(3), J(1))
        self.assertEqual(J(12) >> divBy(0) >> divBy(6), N)

        from hask3.Data.List import replicate
        self.assertEqual(L[1, 2] >> replicate(2) >> replicate(2),
                L[1, 1, 1, 1, 2, 2, 2, 2])

        class Person:
            def __init__(self, name, age):
                self.name = name
                self.age = age

        instance(Eq, Person).where(
            eq = lambda p1, p2: p1.name == p2.name and p1.age == p2.age
        )

        self.assertFalse(Person("Philip Wadler", 59) == Person("Simon Peyton Jones", 57))
Пример #6
0
    def test_examples(self):
        @sig(H/ int >> int >> t(Maybe, int))
        def safe_div(x, y):
            return Nothing if y == 0 else Just(x//y)

        from hask3.Data.Maybe import mapMaybe
        self.assertEqual(mapMaybe(safe_div(12)) % L[0, 1, 3, 0, 6],
                         L[12, 4, 2])

        from hask3.Data.List import isInfixOf
        self.assertTrue(isInfixOf(L[2, 8], L[1, 4, 6, 2, 8, 3, 7]))

        from hask3.Control.Monad import join
        self.assertEqual(join(Just(Just(1))), Just(1))

        from hask3.Prelude import flip
        from hask3.Data.Tuple import snd
        from hask3.Python.builtins import divmod, hex

        hexMod = hex * snd * flip(divmod, 16)
        self.assertEqual(hexMod(24), '0x8')
Пример #7
0
    def test_building_lists(self):
        from hask3.Data.List import scanl, scanl1, scanr, scanr1, mapAccumL  # noqa: F401
        from hask3.Data.List import mapAccumR, iterate, repeat, replicate, cycle  # noqa: F401
        from hask3.Data.List import unfoldr

        plus_one = (lambda x: x + 1)**(H / int >> int)
        self.assertEquals(iterate(plus_one, 0)[:10], L[range(10)])
        self.assertEquals(iterate(__ + 1, 0)[:10], L[range(10)])

        uf = (lambda x: Nothing if x > 5 else Just((x+1, x+1))) ** \
                (H/ int >> t(Maybe, (int, int)))
        self.assertEquals(L[[]], unfoldr(uf, 6))
        self.assertEquals(L[1, ..., 6], unfoldr(uf, 0))
Пример #8
0
    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))
Пример #9
0
 def safe_div(x, y):
     return Nothing if y == 0 else Just(x//y)
Пример #10
0
    def test_functions(self):
        from hask3.Data.Maybe import maybe, isJust, isNothing, fromJust
        from hask3.Data.Maybe import fromMaybe
        from hask3.Data.Maybe import listToMaybe, maybeToList, catMaybes
        from hask3.Data.Maybe import mapMaybe

        self.assertTrue(isJust(Just(1)))
        self.assertTrue(isJust(Just(Nothing)))
        self.assertFalse(isJust(Nothing))
        self.assertFalse(isNothing(Just(1)))
        self.assertFalse(isNothing(Just(Nothing)))
        self.assertTrue(isNothing(Nothing))
        self.assertEqual(fromJust(Just("bird")), "bird")
        self.assertEqual(fromJust(Just(Nothing)), Nothing)
        with self.assertRaises(ValueError):
            fromJust(Nothing)

        self.assertEqual(2, maybe(0, (__ + 1), Just(1)))
        self.assertEqual(0, maybe(0, (__ + 1)) % Nothing)
        self.assertEqual(Nothing, listToMaybe(L[[]]))
        self.assertEqual(Just("a"), listToMaybe(L[["a"]]))
        self.assertEqual(Just("a"), listToMaybe(L["a", "b"]))
        self.assertEqual(Just(1), listToMaybe(L[1, ...]))
        self.assertEqual(L[[]], maybeToList(Nothing))
        self.assertEqual(L[[1]], maybeToList(Just(1)))
        self.assertEqual(L[[]], catMaybes(L[[]]))
        self.assertEqual(L[[]], catMaybes(L[Nothing, Nothing]))
        self.assertEqual(L[1, 2], catMaybes(L[Just(1), Just(2)]))
        self.assertEqual(L[1, 2], catMaybes(L[Just(1), Nothing, Just(2)]))

        from hask3.Prelude import const
        self.assertEqual(L[[]], mapMaybe(const(Nothing), L[1, 2]))
        self.assertEqual(L[1, 2], mapMaybe(Just, L[1, 2]))
        self.assertEqual(L[[]], mapMaybe(Just, L[[]]))

        f = (lambda x: Just(x) if x > 3 else Nothing) \
            ** (H/ int >> t(Maybe, int))
        self.assertEqual(L[4, 5], mapMaybe(f, L[1, ..., 5]))
        self.assertEqual(L[[]], mapMaybe(f, L[1, ..., 3]))

        self.assertEqual(1, fromMaybe(1, Nothing))
        self.assertEqual(2, fromMaybe(1, Just(2)))
Пример #11
0
 def safediv(x, y):
     return Just(x // y) if y != 0 else Nothing
Пример #12
0
    def test_monad(self):
        f = (lambda x: Just(str(x)))**(H / int >> t(Maybe, str))
        g = (lambda x: Just(x * 10))**(H / int >> t(Maybe, int))
        self.assertEqual(Just("1"), Just(1) >> f)
        self.assertEqual(Just(10), Just(1) >> g)
        self.assertEqual(Just(1000), Just(1) >> g >> g >> g)

        @sig(H[(Num, "a")] / "a" >> "a" >> t(Maybe, "a"))
        def safediv(x, y):
            return Just(x // y) if y != 0 else Nothing

        from hask3.Prelude import flip
        s = flip(safediv)
        self.assertEqual(Just(3), Just(9) >> s(3))
        self.assertEqual(Just(1), Just(9) >> s(3) >> s(3))
        self.assertEqual(Nothing, Just(9) >> s(0) >> s(3))
        self.assertEqual(Nothing, Nothing >> s(3) >> s(3))

        # monad laws
        s_composed = (lambda x: s(3, x) >> s(3))**(H / int >> t(Maybe, int))
        self.assertEqual(Just(2), Just(2) >> Just)
        self.assertEqual(Nothing, Nothing >> Just)
        self.assertEqual(Just(4) >> s(2), s(2, 4))
        self.assertEqual(Just(1), (Just(9) >> s(3)) >> s(3))
        self.assertEqual(Just(1), Just(9) >> s_composed)
        self.assertEqual(Nothing, (Nothing >> s(3)) >> s(3))
        self.assertEqual(Nothing, Nothing >> s_composed)

        from hask3.Control.Monad import join, liftM
        self.assertEqual(join(Just(Just(1))), Just(1))
        self.assertEqual(join(Just(Nothing)), Nothing)
        self.assertEqual(liftM(__ + 1, Just(1)), Just(2))
        self.assertEqual(liftM(__ + 1, Nothing), Nothing)
Пример #13
0
    def test_functor(self):
        from hask3.Prelude import id, fmap
        plus1 = (lambda x: x + 1)**(H / int >> int)
        toStr = str**(H / int >> str)

        self.assertEqual(Just(Just(2)), fmap(Just, Just(2)))
        self.assertEqual(Just(3), plus1 * Just(2))
        self.assertEqual(Just("1"), toStr * Just(1))
        self.assertEqual(Just("3"), (toStr * plus1) * Just(2))

        # functor laws
        self.assertEqual(fmap(id, Just(4)), Just(4))
        self.assertEqual(fmap(id, Nothing), Nothing)
        self.assertEqual(id * Just(4), Just(4))
        self.assertEqual(id * Nothing, Nothing)
        self.assertEqual(fmap(toStr, fmap(plus1, Just(2))),
                         fmap(toStr * plus1, Just(2)))
        self.assertEqual((toStr * (plus1 * Just(2))),
                         (toStr * plus1) * Just(2))
Пример #14
0
    def test_sig(self):
        @sig(H/ "a" >> "b" >> "a")
        def const(x, y):
            return x
        self.assertEqual(const(1, 2), 1)

        def const(x, y):
            return x
        const = const ** (H/ "a" >> "b" >> "a")
        self.assertEqual(const(1, 2), 1)

        f = (lambda x, y: x + y) ** (H/ int >> int >> int)
        self.assertEqual(5, f(2, 3))
        with self.assertRaises(TypeError):
            f(9, 1.0)

        g = (lambda a, b, c: a // (b + c)) ** (H/ int >> int >> int >> int)
        self.assertEqual(g(10, 2, 3), 2)
        part_g = g(12)
        self.assertEqual(part_g(2, 2), 3)
        self.assertEqual(g(20, 1)(4), 4)
        self.assertEqual(Just * Just * Just * Just % 77, Just(Just(Just(Just(77)))))

        # add two ints together
        @sig(H/ int >> int >> int)
        def add(x, y):
            return x + y

        # reverse order of arguments to a function
        @sig(H/ (H/ "a" >> "b" >> "c") >> "b" >> "a" >> "c")
        def flip(f, b, a):
            return f(a, b)

        # map a Python (untyped) function over a Python (untyped) set
        @sig(H/ func >> set >> set)
        def set_map(fn, lst):
            return set((fn(x) for x in lst))

        # map a typed function over a List
        @sig(H/ (H/ "a" >> "b") >> ["a"] >> ["b"])
        def map(f, xs):
            return L[(f(x) for x in xs)]

        # type signature with an Eq constraint
        @sig(H[(Eq, "a")]/ "a" >> ["a"] >> bool)
        def not_in(y, xs):
            return not any((x == y for x in xs))

        # type signature with a type constructor (Maybe) that has type arguments
        @sig(H/ int >> int >> t(Maybe, int))
        def safe_div(x, y):
            return Nothing if y == 0 else Just(x//y)

        # type signature for a function that returns nothing
        @sig(H/ int >> None)
        def launch_missiles(num_missiles):
            return

        Ratio, R =\
                data.Ratio("a") == d.R("a", "a") & deriving(Eq)

        Rational = t(Ratio, int)


        @sig(H/ Rational >> Rational >> Rational)
        def addRational(rat1, rat2):
            pass

        from hask3.Prelude import flip
        h = (lambda x, y: x / y) ** (H/ float >> float >> float)
        self.assertEqual(h(3.0) * h(6.0) * flip(h, 2.0) % 36.0, 9.0)
Пример #15
0
 def default_to_zero(x):
     return ~(caseof(x)
                 | m(Just(m.x)) >> p.x
                 | m(Nothing)   >> 0)
Пример #16
0
    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})
Пример #17
0
 def test_eq(self):
     self.assertEqual(Nothing, Nothing)
     self.assertEqual(Just(3), Just(3))
     self.assertEqual(Just("3"), Just("3"))
     self.assertNotEqual(Just(1), Just(3))
     self.assertNotEqual(Just(3), Nothing)
     self.assertNotEqual(Nothing, Just(0))
     self.assertTrue(Just(1) == Just(1))
     self.assertFalse(Just(1) == Just(2))
     self.assertTrue(Nothing == Nothing or Nothing != Nothing)
     self.assertTrue(Just(1) == Just(1) or Just(1) != Just(1))
     self.assertFalse(Nothing == Nothing and Nothing != Nothing)
     self.assertFalse(Just(1) == Just(1) and Just(1) != Just(1))
     with self.assertRaises(TypeError):
         Just(1) == Just("1")
     with self.assertRaises(TypeError):
         Just(1) == Just(1.0)
     with self.assertRaises(TypeError):
         Nothing == None  # noqa
     with self.assertRaises(TypeError):
         Nothing == 1
     with self.assertRaises(TypeError):
         Just(1) == 1
Пример #18
0
    def test_ord(self):
        self.assertTrue(Nothing < Just(0))
        self.assertTrue(Nothing < Just("a"))
        self.assertTrue(Nothing < Just(-float("inf")))
        self.assertTrue(Nothing <= Just(0))
        self.assertTrue(Nothing <= Just("a"))
        self.assertTrue(Nothing <= Just(-float("inf")))
        self.assertTrue(Nothing >= Nothing and Nothing <= Nothing)
        self.assertFalse(Nothing > Just(0))
        self.assertFalse(Nothing > Just("a"))
        self.assertFalse(Nothing > Just(-float("inf")))
        self.assertFalse(Nothing >= Just(0))
        self.assertFalse(Nothing >= Just("a"))
        self.assertFalse(Nothing >= Just(-float("inf")))
        self.assertFalse(Nothing > Nothing or Nothing < Nothing)

        self.assertTrue(Just(1) > Just(0))
        self.assertTrue(Just(Just(1)) > Just(Nothing))
        self.assertTrue(Just(Just(Nothing)) > Just(Nothing))
        self.assertTrue(Just(1) >= Just(0))
        self.assertTrue(Just(1) >= Just(1))
        self.assertTrue(Just(Just(1)) >= Just(Nothing))
        self.assertTrue(Just(Just(Nothing)) >= Just(Nothing))
        self.assertTrue(Just(Just(Nothing)) >= Just(Just(Nothing)))
        self.assertFalse(Just(0) > Just(1))
        self.assertFalse(Just(0) > Just(0))
        self.assertFalse(Just(Nothing) > Just(Just(1)))
        self.assertFalse(Just(Nothing) > Just(Just(Nothing)))
        self.assertFalse(Just(0) >= Just(1))
        self.assertFalse(Just(Nothing) >= Just(Just(1)))
        self.assertFalse(Just(Nothing) >= Just(Just(Nothing)))

        self.assertTrue(Just(0) < Just(1))
        self.assertTrue(Just(Nothing) < Just(Just(1)))
        self.assertTrue(Just(Nothing) < Just(Just(Nothing)))
        self.assertTrue(Just(0) <= Just(1))
        self.assertTrue(Just(Nothing) <= Just(Just(1)))
        self.assertTrue(Just(Nothing) <= Just(Just(Nothing)))
        self.assertFalse(Just(1) < Just(0))
        self.assertFalse(Just(1) < Just(1))
        self.assertFalse(Just(Just(1)) < Just(Nothing))
        self.assertFalse(Just(Just(Nothing)) < Just(Nothing))
        self.assertFalse(Just(1) <= Just(0))
        self.assertTrue(Just(1) <= Just(1))
        self.assertFalse(Just(Just(1)) <= Just(Nothing))
        self.assertFalse(Just(Just(Nothing)) <= Just(Nothing))
        self.assertTrue(Just(Just(Nothing)) <= Just(Just(Nothing)))

        with self.assertRaises(TypeError):
            Just(1) > Just(1.0)
        with self.assertRaises(TypeError):
            Just(1) >= Just(1.0)
        with self.assertRaises(TypeError):
            Just(1) < Just(1.0)
        with self.assertRaises(TypeError):
            Just(1) <= Just(1.0)
        with self.assertRaises(TypeError):
            Just(1) > Just(Just(1))
        with self.assertRaises(TypeError):
            Just(1) >= Just(Just(1))
        with self.assertRaises(TypeError):
            Just(1) < Just(Just(1))
        with self.assertRaises(TypeError):
            Just(1) <= Just(Just(1))
Пример #19
0
    def test_caseof(self):
        # literal matching
        self.assertEqual(1, ~(caseof("a") | m("a") >> 1))
        self.assertEqual(
            1, ~(caseof(2.0)
                 | m(2.0) >> ~(caseof("a")
                               | m("b") >> 3
                               | m("a") >> 1)
                 | m(2.0) >> 2))
        self.assertEqual(
            "x", ~(caseof(Just("x"))
                   | m(Nothing) >> False
                   | m(Just("x")) >> "x"))
        self.assertEqual(1, ~(caseof([1, 2])
                              | m((1, 2)) >> 2
                              | m([1, 2]) >> 1))
        self.assertEqual(
            True, ~(caseof(GT)
                    | m(LT) >> False
                    | m(EQ) >> False
                    | m(GT) >> True))
        self.assertEqual(
            2, ~(caseof((1, 2, 3))
                 | m((1, 2)) >> 1
                 | m((1, 2, 3)) >> 2))

        with self.assertRaises(IncompletePatternError):
            ~(caseof(1) | m(2) >> 2)

        # matches with wildcard
        self.assertEqual(1, ~(caseof(1) | m(m._) >> 1 | m(1) >> 2))
        self.assertEqual(
            True, ~(caseof(GT)
                    | m(LT) >> False
                    | m(EQ) >> False
                    | m(m._) >> True))
        self.assertEqual(
            False, ~(caseof(GT)
                     | m(LT) >> False
                     | m(m._) >> False
                     | m(GT) >> True))
        self.assertEqual(
            2, ~(caseof((1, 2, 3))
                 | m((2, 1, 3)) >> 1
                 | m((1, m._, 3)) >> 2
                 | m((1, 2, 3)) >> 3))

        # variable bind
        self.assertEqual(("b", "a"), ~(caseof(("a", "b"))
                                       | m((m.x, m.y)) >> (p.y, p.x)
                                       | m(m._) >> None))
        self.assertEqual(
            1, ~(caseof(Just(1))
                 | m(Just(m.x)) >> p.x
                 | m(Nothing) >> 0))
        self.assertEqual(
            Just(0), ~(caseof(Nothing)
                       | m(Just(m.x)) >> Just(p.x + 1)
                       | m(Nothing) >> Just(0)))
        self.assertEqual(1, ~(caseof(2) | m((m.a, m.a)) >> p.a | m(2) >> 1))
        self.assertEqual(
            1, ~(caseof(Just(10))
                 | m(Just(m.a)) >> ~(caseof(1)
                                     | m(m.a) >> p.a
                                     | m(m._) >> False)
                 | m(Nothing) >> 11))

        # cons matches
        self.assertEqual([3], ~(caseof([1, 2, 3])
                                | m(1 ^ (2 ^ m.x)) >> p.x
                                | m(m.x) >> False))
        self.assertEqual([3, 2, 1], ~(caseof([3, 2, 1])
                                      | m(m.a ^ (2 ^ m.c)) >> [p.a, 2, p.c[0]]
                                      | m(m.x) >> False))
        self.assertEqual([3, 2, [1, 0]],
                         ~(caseof([3, 2, 1, 0])
                           | m(m.a ^ (m.b ^ m.c)) >> [p.a, p.b, p.c]
                           | m(m.x) >> False))
        self.assertEqual(
            L[3, 2, 1], ~(caseof(L[3, 2, 1, 0])
                          | m(m.a ^ (m.b ^ m.c)) >> L[p.a, p.b, p.c[0]]
                          | m(m.x) >> False))
        self.assertEqual(
            1, ~(caseof(L[1, ...])
                 | m(m.a ^ m.b) >> p.a
                 | m(m.a) >> False))
        self.assertTrue(~(caseof(L[[]])
                          | m(m.a ^ m.b) >> False
                          | m(m.a) >> True))

        with self.assertRaises(SyntaxError):
            ~(caseof((1, 2)) | m((m.a, m.a)) >> p.a | m(1) >> 1)
        with self.assertRaises(SyntaxError):
            ~(caseof([1, 2, 3, 4])
              | m(m.a ^ m.b ^ m.c) >> True
              | m(m.x) >> False)
        with self.assertRaises(SyntaxError):
            ~(caseof(L[1, 2, 2]) | m(m.a ^ 1) >> False | m(m.a) >> True)