package haskell.prelude;

import haskell.test.HaskellTestCase;

public class MaybeTest extends HaskellTestCase {

    public void testNothing() {
        assertNull(Maybe.Nothing().x);
    }

    public void testJust() {
        assertFalse(Maybe.Just(Bool.False()).x);
        assertTrue (Maybe.Just(Bool.True()).x);
    }

    public void testMaybe() {
        final Maybe<Bool> Nothing = Maybe.Nothing();
        final Function<Bool, Maybe<Bool>> f
                = Maybe.<Bool>Just()._dot_(Bool.not());
        assertEquals(Nothing,
                Maybe.maybe(Nothing, f, Nothing));
        assertEquals(Maybe.Just(Bool.True()),
                Maybe.maybe(Nothing, f, Maybe.Just(Bool.False())));
    }

    public void testCategory() {
        final Function<Bool, Maybe<Bool>> f
                = Maybe.<Bool>Just()._dot_(Bool.not());
        final Function<Bool, Maybe<Int>> g
                = Maybe.<Int>Just()._dot_(Bool.Enum().fromEnum());
        final Bool x = Bool.True();
        final Maybe<Bool> m = Maybe.Just(x);
        // (return x) >>= f == f x
        assertEquals(Maybe.return_(x)._bind_(f), f.apply(x));
        // m >>= return == m
        assertEquals(m._bind_(Maybe.<Bool, Bool>Monad2().return_()), m);
        // (m >>= f) >== g == m >> (\x -> f x >>= g)
        assertEquals(m._bind_(f)._bind_(g),
                m._bind_(new Function<Bool, Maybe<Int>>() {
            @Override
            public Maybe<Int> apply(Bool x) {
                return f.apply(x)._bind_(g);
            }
        }));
    }

}
