// 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 }
/// <summary> /// (<$) /// <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 }
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)); } }
// 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 }
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 }
/// <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 }
/// <summary> /// (<**>) /// <para>A variant of (<*>) 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 }
/// <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 }
/// <summary>(<&>)</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 }
/// <summary> /// ($>) /// <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 }