{"action":"created","issue":{"url":"https://api.github.com/repos/haskell-servant/servant/issues/734","repository_url":"https://api.github.com/repos/haskell-servant/servant","labels_url":"https://api.github.com/repos/haskell-servant/servant/issues/734/labels{/name}","comments_url":"https://api.github.com/repos/haskell-servant/servant/issues/734/comments","events_url":"https://api.github.com/repos/haskell-servant/servant/issues/734/events","html_url":"https://github.com/haskell-servant/servant/issues/734","id":225013792,"number":734,"title":"Instances for Enter are secretly overlapping","user":{"login":"fizruk","id":686582,"avatar_url":"https://avatars2.githubusercontent.com/u/686582?v=3","gravatar_id":"","url":"https://api.github.com/users/fizruk","html_url":"https://github.com/fizruk","followers_url":"https://api.github.com/users/fizruk/followers","following_url":"https://api.github.com/users/fizruk/following{/other_user}","gists_url":"https://api.github.com/users/fizruk/gists{/gist_id}","starred_url":"https://api.github.com/users/fizruk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fizruk/subscriptions","organizations_url":"https://api.github.com/users/fizruk/orgs","repos_url":"https://api.github.com/users/fizruk/repos","events_url":"https://api.github.com/users/fizruk/events{/privacy}","received_events_url":"https://api.github.com/users/fizruk/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":10,"created_at":"2017-04-28T08:30:51Z","updated_at":"2017-04-28T11:58:11Z","closed_at":null,"body":"Turns out these two instances secretly overlap:\r\n\r\n```haskell\r\ninstance (Enter b arg ret) => Enter (a -> b) arg (a -> ret)\r\ninstance Enter (m a) (m :~> n) (n a)\r\n```\r\n\r\nIt happens only when `m ~ n` and I suspect that's why no one noticed that so far.\r\n\r\nIn the \"real world\" this results in non-descriptive type errors like this:\r\n\r\n```\r\n    • Couldn't match type ‘App’ with ‘(->) (Maybe Param)’\r\n        arising from a use of ‘enter’\r\n    • In the expression: enter (Nat id :: App :~> App) server\r\n      In an equation for ...\r\n```\r\n\r\nThis prevents me from applying `App :~> App` transformation to handlers directly.\r\nCurrently I work around this by using a pair of transformation:\r\n\r\n```haskell\r\nNat IdentityT :: App :~> IdentityT App\r\n\r\nNat (f . runIdentityT) :: IdentityT App :~> App\r\n```\r\n\r\ninstead of just\r\n\r\n```haskell\r\nNat f :: App :~> App\r\n```\r\n\r\nUnfortunately I don't have a minimal failing test case at this moment. For instance, this works just fine:\r\n\r\n```\r\n>>> :set -XDataKinds\r\n>>> :set -XTypeOperators\r\n>>> import Servant\r\n>>> type Endpoint1 = QueryParam \"param\" Int :> Get '[JSON] NoContent\r\n>>> type Endpoint2 = QueryParam \"param\" String :> Get '[JSON] NoContent\r\n>>> type API = Endpoint1 :<|> Endpoint2\r\n>>> data App a\r\n>>> type S layout = ServerT layout App\r\n>>> server :: S API; server = undefined\r\n>>> :t enter (Nat id :: App :~> App) server\r\nenter (Nat id :: App :~> App) server\r\n  :: (Maybe Int -> App NoContent)\r\n     :<|> (Maybe [Char] -> App NoContent)\r\n```\r\n\r\nPerhaps there's something extra in my project's API that prevents GHC to infer types correctly."},"comment":{"url":"https://api.github.com/repos/haskell-servant/servant/issues/comments/297979740","html_url":"https://github.com/haskell-servant/servant/issues/734#issuecomment-297979740","issue_url":"https://api.github.com/repos/haskell-servant/servant/issues/734","id":297979740,"user":{"login":"fizruk","id":686582,"avatar_url":"https://avatars2.githubusercontent.com/u/686582?v=3","gravatar_id":"","url":"https://api.github.com/users/fizruk","html_url":"https://github.com/fizruk","followers_url":"https://api.github.com/users/fizruk/followers","following_url":"https://api.github.com/users/fizruk/following{/other_user}","gists_url":"https://api.github.com/users/fizruk/gists{/gist_id}","starred_url":"https://api.github.com/users/fizruk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fizruk/subscriptions","organizations_url":"https://api.github.com/users/fizruk/orgs","repos_url":"https://api.github.com/users/fizruk/repos","events_url":"https://api.github.com/users/fizruk/events{/privacy}","received_events_url":"https://api.github.com/users/fizruk/received_events","type":"User","site_admin":false},"created_at":"2017-04-28T11:58:11Z","updated_at":"2017-04-28T11:58:11Z","body":"@phadej yes, that's a step in the right direction and that approach might probably solve `Enter`. However we also need to solve the situation with `:>`. IMO, the worst thing about `:>` is that it mixes methods and parameters, resulting in an ugly `ServerT` we have today.\r\n\r\n@arianvp \r\n\r\n> This would mean your server implementation does not have to exactly match the nesting and order of how your API is defined.\r\n\r\nThis one sounds like ambiguous types pain :)\r\n\r\n> you could add a type level proof that no routes overlap\r\n\r\nIt is possible for Servant, and it's been discussed before (probably on IRC). Just no one has taken this task upon himself yet, I guess.\r\n\r\n> some-of-products like structure\r\n\r\nI suggest there's more to API than sum-of-products. I think API is more like sum of endpoints. Currently we mix all endpoint's properties (path segments, parameters, methods) together, but it does not seem to work out nice. I think we have to make endpoints more structured.\r\n\r\nP.S. We probably should move discussion elsewhere."}}
{"actor":{"display_login":"fizruk"}}