예제 #1
0
        /// <summary>
        /// "Applicative" instance for HaxlFetch.
        /// </summary>
        /// <remarks>
        /// This isn't a true applicative instance; we don't have:
        ///
        /// > (<*>) :: f (a -> b) -> f a -> f b
        ///
        /// In Haskell Haxl, the applicative instance is used to keep fetched values in scope:
        ///
        /// > (a, b) <- (,) <$> fetch1 <*> fetch2
        ///
        /// C# can't do nested lambda scoping, and uses transparent identifers instead.
        /// Because the transparent identifers aren't accessible to us, we use our own scoping system.
        ///
        /// This means our (a -> b) function is *always* (Scope -> Scope);
        /// we therefore can write our "Applicative" instance as simply a function that takes two Fetches.
        /// </remarks>
        public static Haxl Applicative(this Haxl fetch1, Haxl fetch2)
        {
            return(Haxl.FromFunc((cache, logger) =>
            {
                var result1 = fetch1.Result(cache, logger);
                var result2 = fetch2.Result(cache, logger);
                return result1.Match
                (
                    done1 => result2.Match <Result>
                    (
                        done2 => Done.New(compose(done2.AddToScope, done1.AddToScope)),
                        blocked2 => Blocked.New(blocked2.BlockedRequests, blocked2.Continue.Map(done1.AddToScope))
                    ),

                    blocked1 => result2.Match <Result>
                    (
                        done2 => Blocked.New(blocked1.BlockedRequests, blocked1.Continue.Map(done2.AddToScope)),
                        blocked2 => Blocked.New(
                            blocked1.BlockedRequests.Concat(blocked2.BlockedRequests),
                            blocked1.Continue.Applicative(blocked2.Continue)
                            )
                    )
                );
            }));
        }
예제 #2
0
 /// <summary>
 /// Monad instance for HaxlFetch.
 /// </summary>
 public static Haxl Bind(this Haxl fetch, Func <Scope, Haxl> bind)
 {
     return(Haxl.FromFunc((cache, logger) =>
     {
         var result = fetch.Result(cache, logger);
         return result.Match(
             done => bind(done.AddToScope(Scope.New())).Result(cache, logger),
             blocked => Blocked.New(blocked.BlockedRequests, blocked.Continue.Bind(bind))
             );
     }));
 }
예제 #3
0
        /// <summary>
        /// Repeatedly fetches requests until we have the result.
        /// </summary>
        public static async Task <Scope> Run(Haxl fetch, Scope scope, Func <IEnumerable <BlockedRequest>, Task> fetcher, HaxlCache cache, Action <HaxlLogEntry> logger)
        {
            var result = fetch.Result(cache, logger);

            return(await result.Match(
                       done => Task.FromResult(done.AddToScope(scope)),
                       async blocked =>
            {
                await fetcher(blocked.BlockedRequests);
                return await Run(blocked.Continue, scope, fetcher, cache, logger);
            }
                       ));
        }
예제 #4
0
        /// <summary>
        /// Converts a list of applicative groups into a Haxl monad.
        /// </summary>
        public static Haxl ToFetch(List <ApplicativeGroup> split, string parentBind, Scope parentScope)
        {
            if (parentScope == null)
            {
                parentScope = Scope.New();
            }
            Haxl finalFetch = null;
            Action <Func <Scope, Haxl> > bindToFinal = f =>
            {
                finalFetch = finalFetch == null?f(parentScope) : finalFetch.Bind(f);
            };

            foreach (var applicative in split)
            {
                bindToFinal(ApplicativeToHaxl(applicative, parentBind));
            }
            return(finalFetch);
        }
예제 #5
0
        /// <summary>
        /// Folds an applicative group into a Haxl monad.
        /// </summary>
        public static Func <Scope, Haxl> ApplicativeToHaxl(ApplicativeGroup applicative, string parentBind)
        {
            var expressions = applicative.Expressions;

            if (applicative.Expressions.Count == 1)
            {
                return(StatementToHaxl(expressions.First(), parentBind));
            }
            return(scope => applicative.Expressions.Aggregate
                   (
                       Haxl.FromFunc((c, l) => Done.New(s => s)),
                       (group, be) =>
            {
                var haxl = StatementToHaxl(be, parentBind)(scope);
                return group.Applicative(haxl);
            }
                   ));
        }
예제 #6
0
 /// <summary>
 /// Converts a project expression to Haxl monad.
 /// </summary>
 public static Func <Scope, Haxl> ProjectToHaxl(ProjectStatement project, string parentBind)
 {
     return(scope => Haxl.FromFunc((cache, logger) =>
     {
         var rewritten = RebindToScope.Rebind(project.Expression);
         var result = rewritten.Compile().DynamicInvoke(scope);
         return Done.New(_ =>
         {
             if (project.Expression.BindVariable == HAXL_RESULT_NAME &&
                 !scope.IsRoot &&
                 parentBind != null)
             {
                 return scope.WriteParent(parentBind, result);
             }
             return scope.Add(project.Expression.BindVariable, result);
         });
     }));
 }
예제 #7
0
 private Blocked(IEnumerable <BlockedRequest> blocked, Haxl cont)
 {
     BlockedRequests = blocked;
     Continue        = cont;
 }
예제 #8
0
 public static Blocked New(IEnumerable <BlockedRequest> blocked, Haxl cont)
 {
     return(new Blocked(blocked, cont));
 }