Advertisement
Guest User

Untitled

a guest
Feb 14th, 2016
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.10 KB | None | 0 0
  1. {-# LANGUAGE LambdaCase, KindSignatures, DataKinds, ScopedTypeVariables, OverloadedStrings, TypeOperators, FlexibleInstances #-}
  2.  
  3. import Control.Applicative
  4. import Data.Proxy
  5. import qualified Data.Text as Text
  6. import Data.Text (Text)
  7. import GHC.TypeLits
  8. import Network.Wai
  9.  
  10. -- For sanity (see later)
  11. (<&>) :: Functor f => f a -> (a -> b) -> f b
  12. (<&>) = flip fmap
  13.  
  14. type Segment = Text
  15.  
  16. type Path = [ Segment ]
  17.  
  18. -- Application with the current path included.
  19. type RoutingApplication = Path -> Application
  20.  
  21. -- Given the router type and a path,
  22. -- return a function that will perform the routing if applicable.
  23. class Router r where
  24. route :: proxy r -> Path -> Maybe (r -> RoutingApplication)
  25.  
  26. type f :> g = f g
  27. infixr 1 :>
  28.  
  29. newtype Raw = Raw Application
  30.  
  31. instance Router Raw where
  32. route _ _ = Just $ \(Raw app) _ -> app
  33.  
  34. newtype Dir (seg :: Symbol) a = Dir a
  35.  
  36. type seg /> g = Dir seg :> g
  37. infixr 1 />
  38.  
  39. instance (KnownSymbol seg, Router next) => Router (seg /> next) where
  40. route _ = \case
  41. s : segs | Text.unpack s == symbolVal (Proxy :: Proxy seg)
  42. -> route (Proxy :: Proxy next) segs <&> \nextRouter (Dir next) (_ : segs) -> nextRouter next segs
  43. _ -> Nothing
  44.  
  45. -- Try to route with r1, or try to route with r2.
  46. data r1 :<|> r2
  47. = r1 :<|> r2
  48.  
  49. infixr 0 :<|>
  50.  
  51. instance (Router r1, Router r2) => Router (r1 :<|> r2) where
  52. route _ path
  53. = routeLeft <|> routeRight
  54. where
  55. routeLeft = route (Proxy :: Proxy r1) path <&> \r1Router (r1 :<|> r2) -> r1Router r1
  56. routeRight = route (Proxy :: Proxy r2) path <&> \r2Router (r1 :<|> r2) -> r2Router r2
  57.  
  58. -- Capture a segment and pass it on.
  59. newtype Capture next = Capture (Segment -> next)
  60.  
  61. instance Router next => Router (Capture next) where
  62. route _ (_ : segs)
  63. = route (Proxy :: Proxy a) segs <&> \nextRouter (Capture f) (seg : segs) -> nextRouter (f seg) segs
  64.  
  65. -- Type operators
  66.  
  67. -- Example
  68.  
  69. type Benaco
  70. = "foo" /> Raw
  71. :<|> Capture :> "baz" /> Raw
  72.  
  73. benacoImpl :: Benaco
  74. benacoImpl
  75. = (Dir $ Raw someApp)
  76. :<|> Capture (\foo -> Dir $ Raw someApp)
  77. where
  78. someApp :: Application
  79. someApp = undefined
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement