Advertisement
Guest User

Untitled

a guest
Dec 1st, 2015
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.88 KB | None | 0 0
  1. {-# LANGUAGE ConstraintKinds #-}
  2. {-# LANGUAGE DataKinds #-}
  3. {-# LANGUAGE FlexibleContexts #-}
  4. {-# LANGUAGE FlexibleInstances #-}
  5. {-# LANGUAGE GADTs #-}
  6. {-# LANGUAGE KindSignatures #-}
  7. {-# LANGUAGE MultiParamTypeClasses #-}
  8. {-# LANGUAGE OverloadedStrings #-}
  9. {-# LANGUAGE RankNTypes #-}
  10. {-# LANGUAGE ScopedTypeVariables #-}
  11. {-# LANGUAGE TypeFamilies #-}
  12. {-# LANGUAGE TypeOperators #-}
  13. -- | Defining dependently typed servers in Servant
  14. --
  15. -- Written by Edsko de Vries <edsko@well-typed.com>, Well-Typed LLP.
  16. module Main (main) where
  17.  
  18. import GHC.Prim (Constraint)
  19. import Data.Text (Text)
  20. import Network.Wai
  21. import Network.Wai.Handler.Warp
  22. import Servant
  23. import Servant.Server.Internal
  24. import Text.Read (readMaybe)
  25. import qualified Data.Text as Text
  26. import qualified Data.ByteString.Lazy.Char8 as BS
  27.  
  28. {-------------------------------------------------------------------------------
  29. Preliminaries
  30. -------------------------------------------------------------------------------}
  31.  
  32. -- | Existential
  33. data Some (f :: * -> *) = forall a. Some (f a)
  34.  
  35. -- | Constraint reification
  36. data Dict (c :: Constraint) where
  37. Dict :: c => Dict c
  38.  
  39. -- | Type level application
  40. type family Apply (f :: * -> *) (a :: *) :: *
  41.  
  42. {-------------------------------------------------------------------------------
  43. Dependent servers
  44. -------------------------------------------------------------------------------}
  45.  
  46. -- | Server dependent on some index @ix@
  47. newtype DepServer (ix :: * -> *) (f :: * -> *) (m :: * -> *) =
  48. DepServer (forall a. ix a -> ServerT (Apply f a) m)
  49.  
  50. -- | Dependent analogue of `HasServer`
  51. class HasDepServer ix f where
  52. hasDepServer :: Proxy f -> ix a -> Dict (HasServer (Apply f a))
  53.  
  54. {-------------------------------------------------------------------------------
  55. Dependent capture
  56. -------------------------------------------------------------------------------}
  57.  
  58. -- | Dependent capture on some index @ix@
  59. data DepCapture (ix :: * -> *) (f :: * -> *)
  60.  
  61. instance (FromText (Some ix), HasDepServer ix f) => HasServer (DepCapture ix f) where
  62. type ServerT (DepCapture ix f) m = DepServer ix f m
  63.  
  64. route Proxy (DepServer subserver) request respond =
  65. case processedPathInfo request of
  66. (p:ps) ->
  67. case fromText p :: Maybe (Some ix) of
  68. Nothing ->
  69. respond $ failWith NotFound
  70. Just (Some (p' :: ix a)) ->
  71. case hasDepServer (Proxy :: Proxy f) p' of
  72. Dict -> route (Proxy :: Proxy (Apply f a))
  73. (subserver p')
  74. request{ pathInfo = ps }
  75. respond
  76. _ ->
  77. respond $ failWith NotFound
  78.  
  79. {-------------------------------------------------------------------------------
  80. Example
  81. -------------------------------------------------------------------------------}
  82.  
  83. data Value :: * -> * where
  84. VStr :: Text -> Value Text
  85. VInt :: Int -> Value Int
  86.  
  87. data Op :: * -> * where
  88. OpEcho :: Op a
  89. OpReverse :: Op Text
  90. OpCaps :: Op Text
  91. OpInc :: Op Int
  92. OpNeg :: Op Int
  93.  
  94. data ExecOp a
  95. type instance Apply ExecOp a = Capture "op" (Op a) :> Get '[PlainText] (Value a)
  96.  
  97. instance HasDepServer Value ExecOp where
  98. hasDepServer _ (VStr _) = Dict
  99. hasDepServer _ (VInt _) = Dict
  100.  
  101. type API = DepCapture Value ExecOp
  102.  
  103. server :: Server API
  104. server = DepServer serveExecOp
  105.  
  106. serveExecOp :: Value a -> Server (Apply ExecOp a)
  107. serveExecOp val op = return $ execOp val op
  108.  
  109. execOp :: Value a -> Op a -> Value a
  110. execOp val OpEcho = val
  111. execOp (VStr str) OpReverse = VStr $ Text.reverse str
  112. execOp (VStr str) OpCaps = VStr $ Text.toUpper str
  113. execOp (VInt i) OpInc = VInt $ i + 1
  114. execOp (VInt i) OpNeg = VInt $ negate i
  115.  
  116. {-------------------------------------------------------------------------------
  117. Parsing and rendering
  118. -------------------------------------------------------------------------------}
  119.  
  120. instance FromText (Some Value) where
  121. fromText t = Just $ case readMaybe (Text.unpack t) of
  122. Just n -> Some $ VInt n
  123. Nothing -> Some $ VStr t
  124.  
  125. instance FromText (Op Text) where
  126. fromText "echo" = Just OpEcho
  127. fromText "reverse" = Just OpReverse
  128. fromText "caps" = Just OpCaps
  129. fromText _ = Nothing
  130.  
  131. instance FromText (Op Int) where
  132. fromText "echo" = Just OpEcho
  133. fromText "inc" = Just OpInc
  134. fromText "neg" = Just OpNeg
  135. fromText _ = Nothing
  136.  
  137. instance MimeRender PlainText (Value Text) where
  138. mimeRender p (VStr t) = mimeRender p t
  139.  
  140. instance MimeRender PlainText (Value Int) where
  141. mimeRender _ (VInt n) = BS.pack (show n)
  142.  
  143. {-------------------------------------------------------------------------------
  144. Main application driver
  145. -------------------------------------------------------------------------------}
  146.  
  147. app :: Application
  148. app = serve (Proxy :: Proxy API) server
  149.  
  150. main :: IO ()
  151. main = run 8081 app
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement