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)
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))
def test_functions(self): from hask3.Prelude import subtract, even, odd, gcd, lcm, id, const, flip from hask3.Prelude import until, asTypeOf, error self.assertEqual(5, subtract(2, 7)) self.assertEqual(-5, subtract(7, 2)) self.assertTrue(even(20) and even(-20)) self.assertFalse(even(21) and even(-21)) self.assertTrue(odd(21) and odd(-21)) self.assertFalse(odd(20) and odd(-20)) self.assertEqual(4, gcd(8, 12)) self.assertEqual(4, gcd(8, 12)) self.assertEqual(2, gcd(-4, 6)) self.assertEqual(8, gcd(8, 0)) self.assertEqual(8, gcd(0, 8)) self.assertEqual(0, gcd(0, 0)) self.assertEqual(12, lcm(6, 4)) self.assertEqual(3, lcm(3, 3)) self.assertEqual(9, lcm(9, 3)) self.assertEqual(2, lcm(1, 2)) self.assertEqual(0, lcm(0, 8)) self.assertEqual(0, lcm(8, 0)) self.assertEqual(0, lcm(0, 0)) self.assertEqual("a", id("a")) self.assertEqual("a", id * id * id % "a") self.assertEqual(1, const(1, 2)) self.assertEqual(1, const(1) * const(3) % "a") self.assertEqual(1, flip(__ - __, 2, 3)) self.assertEqual(1, flip(const, 2, 1)) self.assertEqual(2, flip(flip(const))(2, 1)) self.assertEqual(1, until(__ > 0, __ + 1, -20)) self.assertEqual(-20, until(__ < 0, __ + 1, -20)) self.assertEqual("a", asTypeOf("a", "a")) self.assertEqual(1, asTypeOf(1, 1)) # error with self.assertRaises(Exception): error("") msg = "OUT OF CHEESE ERROR" try: error(msg) except Exception as e: self.assertEqual((msg, ), e.args)
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))
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')
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)