This is a little too advanced for me. I think I vaguely understand the 
concept, 
But I'm not sure how to actually put them together, In fact I couldn't even 
get
this to compile.  :(




{-# Language DeriveFunctor #-}
{-# Language TypeOperators #-}
{-# Language TypeFamilies  #-}

import Data.Functor.Coproduct
import Data.Void
import Control.Monad.Free
import MVC

newtype Remote req resp x = Remote (req, resp -> x)
    deriving (Functor)

type a :++: b = Coproduct a b
type a :+: b = Either a b
data VoidF a

type family OutputsOf a
type instance OutputsOf (Remote reqR respR :++: x) = respR :+: OutputsOf x
type instance OutputsOf (VoidF a)= Void

type family InputsOf a
type instance InputsOf (Remote reqR respR :++: x) = reqR :+: InputsOf x
type instance InputsOf (VoidF a)= Void

serve
    :: (reqLocal -> Free remote respLocal)
    -> Model (reqLocal :+: OutputsOf remote) (respLocal :+: InputsOf remote)
serve = undefined




On Wednesday, April 30, 2014 2:48:27 PM UTC-7, Gabriel Gonzalez wrote:
>
>  There are two answers, which depend on whether or not you want to block 
> on the request to an external service.
>
> Scenario A) You want to block waiting for a response
>
> The solution for this is that the next generalization of `mvc` will 
> replace the `State` layer of the model with a free monad of all possible 
> synchronous interactions.  See this post of mine, which explains the 
> general concept behind this:
>
> http://www.haskellforall.com/2012/07/purify-code-using-free-monads.html
>
> The intended use case for this is interactions with a database (which are 
> supposed to be fast and synchronous).  However, HTTP requests don't really 
> seem appropriate for this scenario since they usually have non-trivial 
> latency and you will freeze your entire web service if you block waiting 
> for a request.
>
> Scenario B) You want to asynchronously wait for a response
>
> The solution for this is to continue to use a `View` and `Controller` to 
> interact with the external service.  This forces you to structure your 
> model so that it doesn't block waiting for the response.
>
> However, it sounds like this would benefit from layering an orthogonal 
> abstraction on top of `mvc` that would let you write code that looks like 
> concurrent synchronous requests but gets compiled to the correct 
> single-threaded formulation in terms of `Model`s, `View`s, and 
> `Controller`s.  The rough outline I'm thinking of is something like:
>
>     -- The base functor for an external request
>     newtype Remote req resp x = Remote (req, respond -> x) deriving 
> (Functor)
>
>     -- A synonym for `Data.Functor.CoProduct` (the sum of two functors)
>     type a :++: b = Data.Functor.Coproduct.CoProduct a b
>
>     -- The empty functor, analogous to `Void`
>     data VoidF a
>
>     -- A synonym for `Either`
>     type a :+: b = Either a b
>
>     -- See below for how to generalize this to an arbitrary number
>     -- of external services using something like type families
>     serve
>         :: (reqLocal -> Free (Remote reqR1 respR1 :++: Remote reqR2 
> respR2 :++: VoidF)  respLocal)
>         -> Model (reqLocal :+: respR1 :+: respR2 :+: Void) (respLocal :+: 
> reqR1 :+: reqR2 :+: Void)
>
> The argument of `serve` would be the handler for each incoming request.  
> It takes an argument of type `reqLocal` (i.e. "request local") and makes a 
> few calls to two external services, and then returns a result of type 
> `respLocal` when it is done handling the request.  Then `serve` takes that 
> handler and compiles it to the equivalent `Model`.
>
> Generalizing this type signature to any number of services should be 
> possible, but I need to think about it some more.  The more general 
> signature might look like this:
>
>     serve
>         :: (reqLocal -> Free remote respLocal)
>         -> Model (reqLocal :+: OutputsOf remote) (respLocal :+: InputsOf 
> remote)
>
> ... where `OutputsOf` and `InputsOf` are type level functions from the 
> coproduct of services to sums of outputs or inputs, respectively:
>
>     type OutputsOf (Remote reqR respR :++: x) = respR :+: OutputsOf x
>     type OutputsOf VoidF = Void
>
>     type InputsOf (Remote reqR respR :++: x) = reqR :+: InputsOf x
>     type InputsOf VoidF = Void
>
> Yeah, I think that would work.  Give me some time and I will try my hand 
> at that and see if I can implement something like `serve`.  Then ideally 
> you would be able to just write something like this:
>
>     let model = serve $ \incoming -> do
>             ...
>             resp1 <- external1 req1
>             ...
>             resp2 <- external2 req2
>             ...
>             return outgoing
>
> You'd still be responsible for providing the appropriate `View`s and 
> `Controller`s, but the hard part of chaining "synchronous" requests 
> together without blocking your `Model` would be done for you and you'd 
> still preserve the purity of the `Model`.
>
> In fact, I wonder if I can use this to simultaneously solve the database 
> interface, too, without having to modify `mvc` at all.  This seems like a 
> much more general solution than I anticipated when I first started writing 
> out this e-mail.
>
> On 4/30/14, 11:03 AM, Kai Wang wrote:
>  
> From the documentation, the "Controller" represents an input to the model, 
> and the "View" is an output.  
> In the context of an RESTful web app, I would map an processed HTTP 
> request (GET/POST/etc) to Controller,
> and rendered HTML/JSON as view. 
>
>  However, real life web app would need much more than that. Often they 
> need additional IO. Say I need to make
> use of some 3rd party web service. Then I would need to send some http 
> request. This request I send is
> an output of my model, but I can hardly call it a "View". How would I deal 
> with situations like this with mvc
> library? Other additional IOs like logging, state persistence also don't 
> fit into the mvc concept very well. 
> How can we add these features?
>  -- 
> You received this message because you are subscribed to the Google Groups 
> "Haskell Pipes" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected] <javascript:>.
> To post to this group, send email to [email protected]<javascript:>
> .
>
>
>  

-- 
You received this message because you are subscribed to the Google Groups 
"Haskell Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].

Reply via email to