예제 #1
0
        /// <summary>
        /// (&lt;$)
        /// <para>a = TResult, b = TSource</para>
        /// <para>Create a new f a from an f b by replacing all of the values in
        /// the f b by a given value of type a.</para>
        /// </summary>
        public static Mayhap <TResult> ReplaceWith <TSource, TResult>(
            TResult value,
            Mayhap <TSource> mayhap)
            where TResult : notnull
        {
            // (<$) :: Functor f => a -> f b -> f a | infixl 4 |
            //
            // (<$) :: a -> f b -> f a
            // (<$) =  fmap . const
            //
            // Replace all locations in the input with the same value. The
            // default definition is fmap . const, but this may be overridden
            // with a more efficient version.
            //
            // Examples:
            //   "xxx" <$ Nothing == Nothing
            //   "xxx" <$ Just 1  == Just "xxx"

#if STRICT_HASKELL
            return(Map(__const, mayhap));

            // NB: this is just (_ => value).
            TResult __const(TSource x) => Thunks <TResult, TSource> .Const1(value, x);
#else
            return(mayhap.Select(_ => value));
#endif
        }
예제 #2
0
        public static Mayhap <TResult> Join <T, TInner, TKey, TResult>(
            this Mayhap <T> @this,
            Mayhap <TInner> inner,
            Func <T, TKey> outerKeySelector,
            Func <TInner, TKey> innerKeySelector,
            Func <T, TInner, TResult> resultSelector)
        {
            Utilities.Guard.NotNull(outerKeySelector, nameof(outerKeySelector));
            Utilities.Guard.NotNull(innerKeySelector, nameof(innerKeySelector));
            Utilities.Guard.NotNull(resultSelector, nameof(resultSelector));

            var comparer = EqualityComparer <TKey> .Default;

            var keyLookup = __getKeyLookup();

            return(@this.SelectMany(__valueSelector, resultSelector));

            Mayhap <TInner> __valueSelector(T outer) => keyLookup(outerKeySelector(outer));

            Func <TKey, Mayhap <TInner> > __getKeyLookup()
            {
                return(outerKey =>
                       inner.Select(innerKeySelector)
                       .Where(innerKey => comparer.Equals(innerKey, outerKey))
                       .ContinueWith(inner));
            }
        }
예제 #3
0
        /// <summary>
        /// pure
        /// <para>Embed pure expressions, ie lift a value.</para>
        /// </summary>
        public static Mayhap <T> Pure <T>(T value)
        {
#if STRICT_HASKELL
            throw new NotImplementedException("Applicative pure");
#else
            return(Mayhap <T> .η(value));
#endif
        }
예제 #4
0
            // First law: the identity map is a fixed point for Select.
            //   fmap id  ==  id
            public static bool IdentityRule <T>(Mayhap <T> mayhap)
            {
#if STRICT_HASKELL
                return(Map(Thunks <T> .Ident, mayhap)
                       == Thunks <Mayhap <T> > .Ident(mayhap));
#else
                return(mayhap.Select(Thunks <T> .Ident)
                       == Thunks <Mayhap <T> > .Ident(mayhap));
#endif
            }
예제 #5
0
            // Second law: Select preserves the composition operator.
            //   fmap (f . g)  ==  fmap f . fmap g
            public static bool CompositionRule <T1, T2, T3>(
                Mayhap <T1> mayhap, Func <T2, T3> f, Func <T1, T2> g)
            {
#if STRICT_HASKELL
                return(Map(x => f(g(x)), mayhap)
                       == Map(f, Map(g, mayhap)));
#else
                return(mayhap.Select(x => f(g(x)))
                       == mayhap.Select(g).Select(f));
#endif
            }
예제 #6
0
        public static Mayhap <TResult> SelectMany <T, TMiddle, TResult>(
            this Mayhap <T> @this,
            Func <T, Mayhap <TMiddle> > selector,
            Func <T, TMiddle, TResult> resultSelector)
        {
            Utilities.Guard.NotNull(selector, nameof(selector));
            Utilities.Guard.NotNull(resultSelector, nameof(resultSelector));

            return(@this.Bind(
                       x => selector(x).Select(
                           middle => resultSelector(x, middle))));
        }
예제 #7
0
        /// <summary>
        /// (&lt;*)
        /// <para>Sequence actions, discarding the value of the second argument.
        /// </para>
        /// </summary>
        public static Mayhap <TSource> Ignore <TSource, TOther>(
            this Mayhap <TSource> @this,
            Mayhap <TOther> other)
        {
            // (<*) :: f a -> f b -> f a
            // (<*) = liftA2 const

#if STRICT_HASKELL
            return(Lift(Thunks <TSource, TOther> .Const1).Invoke(@this, other));
#else
            return(@this);
#endif
        }
예제 #8
0
        public static Mayhap <Mayhap <T> > Optional <T>(this Mayhap <T> @this)
        {
            // optional :: Alternative f => f a -> f (Maybe a)
            // optional v = Just <$> v <|> pure Nothing
            //
            // One or none.

#if STRICT_HASKELL
            return(Map(Mayhap <T> .Some, @this).Otherwise(Pure(Mayhap <T> .None)));
#else
            return(@this.Select(Mayhap <T> .Some).OrElse(Pure(Mayhap <T> .None)));
#endif
        }
예제 #9
0
        /// <summary>many</summary>
        public static Mayhap <IEnumerable <T> > Many <T>(Mayhap <T> mayhap)
        {
            // many :: f a -> f [a]
            // many v = many_v
            //   where
            //     many_v = some_v <|> pure []
            //     some_v = liftA2 (:) v many_v
            //
            // many v = some v <|> pure []
            //
            // Zero or more.

            return(Some(mayhap).Otherwise(EmptyEnumerable <T>()));
        }
예제 #10
0
        /// <summary>
        /// void
        /// <para>a = TSource, () = Unit</para>
        /// <para>Create a new f () from an f a by replacing all of the values
        /// in the f a by ().</para>
        /// </summary>
        public static Mayhap <Unit> Skip <TSource>(
            this Mayhap <TSource> @this)
        {
            // void :: Functor f => f a -> f ()
            // void x = () <$ x
            //
            // void value discards or ignores the result of evaluation, such as
            // the return value of an IO action.

#if STRICT_HASKELL
            return(ReplaceWith(Abc.Unit.Default, @this));
#else
            return(@this.Select(_ => Abc.Unit.Default));
#endif
        }
예제 #11
0
        /// <summary>
        /// (&lt;**&gt;)
        /// <para>A variant of (&lt;*&gt;) with the arguments reversed.</para>
        /// </summary>
        public static Mayhap <TResult> Apply <TSource, TResult>(
            this Mayhap <TSource> @this,
            Mayhap <Func <TSource, TResult> > applicative)
        {
            // (<**>) :: Applicative f => f a -> f (a -> b) -> f b
            // (<**>) = liftA2(\a f -> f a)
            //
            // A variant of '<*>' with the arguments reversed.

#if STRICT_HASKELL
            return(Invoke(applicative, @this));
#else
            return(applicative.Bind(f => @this.Select(f)));
#endif
        }
예제 #12
0
        // Hummm, infinite recursive calls. Clean up
        // https://stackoverflow.com/questions/7671009/some-and-many-functions-from-the-alternative-type-class
        // https://www.reddit.com/r/haskell/comments/b71oje/i_dont_understand_how_some_and_many_from_the/

        /// <summary>some</summary>
        public static Mayhap <IEnumerable <T> > Some <T>(Mayhap <T> mayhap)
        {
            // some :: f a -> f [a]
            // some v = some_v
            //   where
            //     many_v = some_v <|> pure []
            //     some_v = liftA2 (:) v many_v
            //
            // some v = (:) <$> v <*> many v
            //
            // One or more.

            Func <T, IEnumerable <T>, IEnumerable <T> > prepend = (x, y) => y.Prepend(x);

            return(Pure(prepend).Invoke(mayhap, Many(mayhap)));
        }
예제 #13
0
        /// <summary>
        /// fmap
        /// <para>a = TSource, b = TResult</para>
        /// <para>Create a new f b from an f a using the results of calling a
        /// function on every value in the f a.</para>
        /// </summary>
        public static Mayhap <TResult> Map <TSource, TResult>(
            Func <TSource, TResult> mapper,
            Mayhap <TSource> mayhap)
        {
            // fmap :: (a -> b) -> f a -> f b
            //
            // Examples:
            //   fmap (+1) (Just 1)  ==  Just 2
            //   fmap (+1) Nothing   ==  Nothing

#if STRICT_HASKELL
            throw new NotImplementedException("Functor fmap");
#else
            return(mayhap.Select(mapper));
#endif
        }
예제 #14
0
        /// <summary>
        /// (&lt;|&gt;)
        /// </summary>
        public static Mayhap <T> Otherwise <T>(this Mayhap <T> @this, Mayhap <T> other)
        {
            // (<|>) :: f a -> f a -> f a | infixl 3 |
            //
            // An associative binary operation.
            //
            // Examples:
            //   Nothing <|> Nothing == Nothing
            //   Just 1  <|> Nothing == Just 1
            //   Nothing <|> Just 1  == Just 1
            //   Just 1  <|> Just 2  == Just 1

#if STRICT_HASKELL
            throw new NotImplementedException("Alternative <|>");
#else
            return(@this.OrElse(other));
#endif
        }
예제 #15
0
        /// <summary>
        /// ($&gt;)
        /// <para>a = TSource, b = TResult</para>
        /// <para>Create a new f b, from an f a by replacing all of the values
        /// in the f a by a given value of type b.</para>
        /// </summary>
        public static Mayhap <TResult> ReplaceWith <TSource, TResult>(
            this Mayhap <TSource> @this,
            TResult value)
            where TResult : notnull
        {
            // ($>) :: Functor f => f a -> b -> f b | infixl 4 |
            // ($>) = flip (<$)
            //
            // Flipped version of <$.
            //
            // Examples:
            //   Nothing $> "xxx" == Nothing
            //   Just 1 $> "xxx"  == Just "xxx"

#if STRICT_HASKELL
            return(ReplaceWith(value, @this));
#else
            return(@this.Select(_ => value));
#endif
        }
예제 #16
0
        /// <summary>(&lt;&amp;&gt;)</summary>
        public static Mayhap <TResult> Map <TSource, TResult>(
            this Mayhap <TSource> @this,
            Func <TSource, TResult> mapper)
        {
            // [Functor]
            //   (<&>) :: Functor f => f a -> (a -> b) -> f b | infixl 1 |
            //   (<&>) = flip fmap
            //
            //    Flipped version of <$>.
            //
            // Examples:
            //   Just 1  <&> (+1)  ==  Just 2
            //   Nothing <&> (+1)  ==  Nothing

#if STRICT_HASKELL
            return(Map(mapper, @this));
#else
            return(@this.Select(mapper));
#endif
        }
예제 #17
0
        /// <summary>
        /// (*&gt;)
        /// <para>Sequence actions, discarding the value of the first argument.
        /// </para>
        /// </summary>
        public static Mayhap <TResult> ContinueWith <TSource, TResult>(
            this Mayhap <TSource> @this,
            Mayhap <TResult> other)
        {
            // (*>) :: f a -> f b -> f b
            // a1 *> a2 = (id <$ a1) <*> a2
            //
            // This is essentially the same as liftA2 (flip const), but if the
            // Functor instance has an optimized (<$), it may be better to use
            // that instead.Before liftA2 became a method, this definition
            // was strictly better, but now it depends on the functor.For a
            // functor supporting a sharing-enhancing (<$), this definition
            // may reduce allocation by preventing a1 from ever being fully
            // realized. In an implementation with a boring (<$) but an optimizing
            // liftA2, it would likely be better to define (*>) using liftA2.

#if STRICT_HASKELL
            return(Lift(Thunks <TSource, TResult> .Const2).Invoke(@this, other));
#else
            return(other);
#endif
        }
예제 #18
0
 // Identity
 // pure id <*> v = v
 public static bool IdentityRule <T>(Mayhap <T> mayhap)
 {
     return(Pure(Thunks <T> .Ident).Invoke(mayhap)
            == mayhap);
 }