{"action":"created","issue":{"url":"https://api.github.com/repos/haskell-servant/servant/issues/637","repository_url":"https://api.github.com/repos/haskell-servant/servant","labels_url":"https://api.github.com/repos/haskell-servant/servant/issues/637/labels{/name}","comments_url":"https://api.github.com/repos/haskell-servant/servant/issues/637/comments","events_url":"https://api.github.com/repos/haskell-servant/servant/issues/637/events","html_url":"https://github.com/haskell-servant/servant/issues/637","id":190145699,"number":637,"title":"Add Lift","user":{"login":"dmjio","id":875324,"avatar_url":"https://avatars.githubusercontent.com/u/875324?v=3","gravatar_id":"","url":"https://api.github.com/users/dmjio","html_url":"https://github.com/dmjio","followers_url":"https://api.github.com/users/dmjio/followers","following_url":"https://api.github.com/users/dmjio/following{/other_user}","gists_url":"https://api.github.com/users/dmjio/gists{/gist_id}","starred_url":"https://api.github.com/users/dmjio/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dmjio/subscriptions","organizations_url":"https://api.github.com/users/dmjio/orgs","repos_url":"https://api.github.com/users/dmjio/repos","events_url":"https://api.github.com/users/dmjio/events{/privacy}","received_events_url":"https://api.github.com/users/dmjio/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2016-11-17T19:50:03Z","updated_at":"2016-11-17T21:27:08Z","closed_at":null,"body":"Sometimes it's beneficial to have only concrete types expressed inside your servant DSL. \r\n\r\nExample:\r\n```haskell\r\nhandlers :: String :<|> String\r\nhandlers = \"foo\" :<|> \"bar\"\r\n\r\ntype API = \"foo\" :> Get '[JSON] String :<|> \"bar\" :> Get '[JSON] String\r\n```\r\n\r\nServing this DSL will obviously fail since it's not operating inside of `ExceptT ServantErr IO`.\r\n\r\n```haskell\r\nmain :: IO ()\r\nmain = run 3000 $ serve (Proxy :: Proxy API) handlers\r\n\r\n{--\r\nMain.hs:125:46-51: error: …                                                                                                                                                       \r\n    • Couldn't match type ‘[Char]’ with ‘ExceptT ServantErr IO [Char]’                                                                                                            \r\n      Expected type: Server API                                                                                                                                                   \r\n        Actual type: String :<|> String                                                                                                                                           \r\n    • In the second argument of ‘serve’, namely ‘things’                                                                                                                          \r\n      In the second argument of ‘($)’, namely                                                                                                                                     \r\n        ‘serve (Proxy :: Proxy API) things’                                                                                                                                       \r\n      In the expression: run 3000 $ serve (Proxy :: Proxy API) things                                                                                                             \r\nCompilation failed.    \r\n--}\r\n```\r\n\r\nAn initial attempt to transform this DSL into `ExceptT ServantErr IO` using `Nat` and `Enter`'s instance for `(:~>)` will also fail since `String` is a concrete type of kind `*`. `Nat` requires the type it's transforming to be at least `* -> *`.\r\n\r\nFor reference, `Nat` and its `Enter` instance are defined as: \r\n```haskell\r\nnewtype m :~> n = Nat { unNat :: forall a. m a -> n a }\r\ninstance Enter (m a) (m :~> n) (n a) where enter (Nat f) = f    \r\n```\r\n\r\n```haskell\r\nmain :: IO ()\r\nmain = run 3000 $ serve (Proxy :: Proxy API) (enter (Nat return) handlers)\r\n\r\n{--\r\nMain.hs:125:58-63: error: …                                                                                                                                                       \r\n    • Couldn't match type ‘a’ with ‘m0 a’                                                                                                                                         \r\n      ‘a’ is a rigid type variable bound by                                                                                                                                       \r\n        a type expected by the context:                                                                                                                                           \r\n          forall a. m0 a -> n0 a                                                                                                                                                  \r\n        at /Users/dmj/Desktop/falad/Main.hs:125:54                                                                                                                                \r\n      Expected type: m0 a -> n0 a                                                                                                                                                 \r\n        Actual type: a -> n0 a                                                                                                                                                    \r\n    • In the first argument of ‘Nat’, namely ‘return’                                                                                                                             \r\n      In the first argument of ‘enter’, namely ‘(Nat return)’                                                                                                                     \r\n      In the second argument of ‘serve’, namely                                                                                                                                   \r\n        ‘(enter (Nat return) things)’                                                                                                                                             \r\nCompilation failed.       \r\n--}\r\n```\r\n\r\nIf we introduce a type `Lift` with it's own `Enter` instance we can allow arbitrary types to be lifted into `ExceptT ServantErr IO`.\r\n\r\n```haskell\r\nnewtype x :~^ n = Lift { unLift :: forall a. a -> n a }\r\ninstance Enter a (a :~^ n) (n a) where enter (Lift f) = f    \r\n\r\nmain :: IO ()\r\nmain = run 3000 $ serve (Proxy :: Proxy API) (enter (Lift pure) handler)  \r\n\r\n{-- \r\nλ Davids-MacBook-Pro-3 → curl localhost:3000/bar\r\n\"bar\"% \r\n--}\r\n```\r\n\r\nFor reference, here is the `(->)` instance for `Enter`\r\n\r\n```haskell\r\ninstance (Enter b arg ret) => Enter (a -> b) arg (a -> ret) where\r\n    enter arg f a = enter arg (f a)\r\n```\r\n\r\nIt should be possible to map `Identity` (or simply pure) over each `String`, and then use `Nat`, but the `(->)` instance for `Enter` did not allow this.\r\n\r\n```haskell\r\nhandle :: Identity String :<|> Identity String\r\nhandle = enter Identity handlers\r\n\r\n-- Main.hs:132:7-27: error: …                                                                                                                                                     \r\n--     • No instance for (Enter [Char] (a0 -> Identity a0) (Identity String)) arising from a use of ‘enter’\r\n--         (maybe you haven't applied a function to enough arguments?) \r\n--     • In the expression: enter Identity\r\n--       In an equation for ‘foo’: foo = enter Identity handlers\r\n-- Compilation failed. \r\n```"},"comment":{"url":"https://api.github.com/repos/haskell-servant/servant/issues/comments/261374668","html_url":"https://github.com/haskell-servant/servant/issues/637#issuecomment-261374668","issue_url":"https://api.github.com/repos/haskell-servant/servant/issues/637","id":261374668,"user":{"login":"ElvishJerricco","id":1365692,"avatar_url":"https://avatars.githubusercontent.com/u/1365692?v=3","gravatar_id":"","url":"https://api.github.com/users/ElvishJerricco","html_url":"https://github.com/ElvishJerricco","followers_url":"https://api.github.com/users/ElvishJerricco/followers","following_url":"https://api.github.com/users/ElvishJerricco/following{/other_user}","gists_url":"https://api.github.com/users/ElvishJerricco/gists{/gist_id}","starred_url":"https://api.github.com/users/ElvishJerricco/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ElvishJerricco/subscriptions","organizations_url":"https://api.github.com/users/ElvishJerricco/orgs","repos_url":"https://api.github.com/users/ElvishJerricco/repos","events_url":"https://api.github.com/users/ElvishJerricco/events{/privacy}","received_events_url":"https://api.github.com/users/ElvishJerricco/received_events","type":"User","site_admin":false},"created_at":"2016-11-17T21:27:08Z","updated_at":"2016-11-17T21:27:08Z","body":"Don't you need to do `enter (Lift Identity) handlers`?"}}
{"actor":{"display_login":"ElvishJerricco"}}