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_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)
def maybe_fmap(fn, maybe_value): return ~(caseof(maybe_value) | m(N) >> N | m(J(m.x)) >> J(fn(p.x)) )
def default_to_zero(x): return ~(caseof(x) | m(Just(m.x)) >> p.x | m(Nothing) >> 0)
def fib(x): return ~(caseof(x) | m(0) >> 1 | m(1) >> 1 | m(m.n) >> fib(p.n - 2) + fib(p.n - 1) )