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

IsSubAPI constraint #305

Closed
fizruk opened this issue Dec 25, 2015 · 8 comments
Closed

IsSubAPI constraint #305

fizruk opened this issue Dec 25, 2015 · 8 comments

Comments

@fizruk
Copy link
Member

fizruk commented Dec 25, 2015

I am using this currently to tag sub APIs in servant-swagger, but I believe this belongs in servant:

-- | Check whether @sub@ is a sub API of @api@.
type family IsSubAPI sub api :: Constraint where
  IsSubAPI sub api = AllIsElem (EndpointsList sub) api

-- | Check that every element of @xs@ is an endpoint of @api@.
type family AllIsElem xs api :: Constraint where
  AllIsElem '[] api = ()
  AllIsElem (x ': xs) api = (IsElem x api, AllIsElem xs api)

-- | Apply @(e :>)@ to every API in @xs@.
type family MapSub e xs where
  MapSub e '[] = '[]
  MapSub e (x ': xs) = (e :> x) ': MapSub e xs

-- | Append two type-level lists.
type family AppendList xs ys where
  AppendList '[]       ys = ys
  AppendList (x ': xs) ys = x ': AppendList xs ys

-- | Build a list of endpoints from an API.
type family EndpointsList api where
  EndpointsList (a :<|> b) = AppendList (EndpointsList a) (EndpointsList b)
  EndpointsList (e :> a)   = MapSub e (EndpointsList a)
  EndpointsList a = '[a]

I am not sure where to put it though.

@fizruk
Copy link
Member Author

fizruk commented Dec 25, 2015

I guess IsIn from servant-docs would be more appropriate here than IsElem though.

@jkarni
Copy link
Member

jkarni commented Dec 25, 2015

I'm very much in favour of organizing and adding to the type-level functionality bits!

There's a lot of related stuff in Servant.Utils.Links, though as you've pointed out also elsewhere (e.g. servant-docs). Maybe we should have a Servant.Utils.TypeUtils in servant, and move everything in there?

While we're at it, we can maybe generalize some of these functions.

type family Map e xs where
  Map e '[] = '[]
  Map e (x ': xs) = (e x) ': Map e xs

type family All (pred :: k -> Constraint) (ls :: '[k]) :: Constraint where
  All pred '[] = ()
  All pred (x ': xs) = (pred x, All pred xs)

type family Const a b = b

Then MapSub e xs == Map (e :>) xs, and AllIsElem xs api == All Const (Map (Flip (IsElem api))) (there might be partial application issues lurking though).

@alpmestan
Copy link
Contributor

I'm all for putting together a little group of type families that are of interest to people using servant in non trivial ways, including for use in core servant packages.

But please folks, let's not pretend those things are "miscellaneous" -- I suggest we move the links machinery + those things in modules with proper names, without "Utils". I remember seeing a lot of people being thrilled to find out servant supports type-safe links... several weeks/months after they started using it. Let's move all those things in decent modules, Servant.Links etc.

@fizruk
Copy link
Member Author

fizruk commented Dec 26, 2015

I agree that these should not be merely Utils.

How about putting IsElem, IsIn and IsSubAPI into Servant.API.Types or Servant.API.Constraints?

@jkarni
Copy link
Member

jkarni commented Dec 27, 2015

I feel like .Types is traditionally a module containing all the types of a package, whereas here what we mean is that it contains functionality for working with types (which is why I suggested TypeUtils).

@alpmestan
Copy link
Contributor

Typelevel ?

@fizruk
Copy link
Member Author

fizruk commented Dec 29, 2015

I am okay with Servant.API.TypeLevel.

@phadej phadej added this to the 0.10 milestone Jan 16, 2017
@phadej
Copy link
Contributor

phadej commented Jan 16, 2017

Superseded by #345. Closing this.

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

No branches or pull requests

5 participants