Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Servant type family pattern #701

Closed
echatav opened this issue Feb 15, 2017 · 6 comments
Closed

Servant type family pattern #701

echatav opened this issue Feb 15, 2017 · 6 comments

Comments

@echatav
Copy link

echatav commented Feb 15, 2017

Hello, the similarity between handler and client signatures in Servant is very noticeable. Could it be abstracted away? Except for Raw, Vault, RemoteHost, IsSecure, AuthProtect and BasicAuth the type families type Client api and type ServerT api ClientM are the same I think. The exceptions almost seem conspicuous!

@phadej
Copy link
Contributor

phadej commented Feb 15, 2017

So we'd have

type family Signature combinator api where
  Signature (Capture name a) api = a -> api
  Signature (Header name a) api = a -> api

instance ... => HasServer (Capture name a :> api) where
   type ServerT (Capture name a :> api) m = Signature (Capture name a) (ServerT api m)

etc.?

See also fizruk/http-api-data#45 (comment) where we'd have different types for Client and Server.

I hardly see a benefit at this point, fwiw it seems like a wrong thing to abstract over. 👎.

@alpmestan
Copy link
Contributor

@echatav Did you just happen to find the similarity interesting or do you have any motivation for abstracting away the commonalities between both?

What I'd be more interested in, to be honest, is some generic machinery for traversing just API types (e.g to generate docs or client functions), or API types + a matching chain of :<|>-separated stuffs (think server-side handlers), or just chains of :<|>-separated stuffs (think Enter, but better). We have a few isolated solutions for this and it feels like we could do better.

@echatav
Copy link
Author

echatav commented Feb 15, 2017

I'm not going to lobby hard for anything here. I really just found it interesting and was curious if it was already recognized or not. I always try to abstract commonality where possible for DRY, separation of concerns, generalization benefits and because it's just so satisfying. To clarify, if you did have a type family like Signature you wouldn't need associated type families for HasServer or HasClient.

class HasClient api where
  clientWithRoute
    :: Proxy api
    -> Req
    -> SignatureT api ClientM

class HasServer api where
  route
    :: Proxy api
    -> Context context
    -> Delayed env (SignatureT api Handler)
    -> Router env

@alpmestan
Copy link
Contributor

alpmestan commented Feb 15, 2017

Having SignatureT apart for any type families, existing on its own, might actually help. People are often not aware of :kind! in ghci and wonder what an API type gets mapped to through Server or Client. Explaining SignatureT (and :kind!) before surely would help people understand the server and client interpretations.

@jkarni
Copy link
Member

jkarni commented Feb 15, 2017 via email

@phadej
Copy link
Contributor

phadej commented Feb 15, 2017

I'm still not convinced SignatureT is "the right abstraction". Yes, ServerT and Client are close, but sometimes they are different: Raw and e.g. LenientCapture, where ServerT would have Either String a -> ... (i.e. pass the parse error to the handler), but Client only a ->.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants