2 {-# LANGUAGE RankNTypes #-}
4 {-# LANGUAGE UndecidableInstances #-}
6 module Literate.Web.Semantics.Addresser where
10 import Data.Function (id, ($), (.))
11 import Data.Functor ((<$>))
12 import Data.List qualified as List
13 import Data.Maybe (Maybe (..))
14 import Data.Monoid (Monoid (..))
16 import Data.Semigroup (Semigroup (..))
17 import Data.Text qualified as Text
18 import GHC.Generics (Generic)
19 import Literate.Web.Syntaxes
20 import Literate.Web.Types.URL
21 import Symantic qualified as Sym
22 import System.FilePath qualified as Sys
23 import Text.Show (Show (..))
27 -- Interpreter building 'Address'.
28 data Addresser a = Addresser
29 { unAddresser :: forall next. (Address -> next) -> a --> next
32 -- | Nothing is needed at the 'Endpoint' for building an 'Address'.
33 type instance ToFEndpoint Addresser a next = next
35 address :: Addresser a -> a --> Address
36 address router = unAddresser router id
38 instance PathSegmentable Addresser where
39 pathSegment s = Addresser \f -> f Address{addressSegs = [s], addressExts = []}
41 instance Sym.SumFunctor Addresser where
42 a <+> b = Addresser \n -> (unAddresser a n, unAddresser b n)
43 instance Sym.ProductFunctor Addresser where
44 a <.> b = Addresser \k -> unAddresser a \aA -> unAddresser b \bA -> k (aA <> bA)
45 a <. b = Addresser \k -> unAddresser a \aA -> unAddresser b \bA -> k (aA <> bA)
46 a .> b = Addresser \k -> unAddresser a \aA -> unAddresser b \bA -> k (aA <> bA)
51 , Sym.IsToF a ~ 'False
52 , e ~ Sym.EoT (Sym.ADT a)
57 -- dataType :: sem (Sym.EoT (Sym.ADT a)) -> sem a
58 dataType a = Addresser (\a2n -> Sym.funOftof (unAddresser a a2n) . Sym.eotOfadt)
59 instance Sym.IsToF a ~ 'False => Optionable a Addresser where
60 optional aA = Addresser \k -> \case
62 Just a -> unAddresser aA k a
64 instance end ~ Address => Responsable a ts m (Addresser) where
65 response = Addresser ($ mempty)
68 data Address = Address
69 { addressSegs :: [PathSegment]
70 , addressExts :: [PathSegment]
72 deriving (Eq, Ord, Show)
73 instance Semigroup Address where
76 { addressSegs = addressSegs x <> addressSegs y
77 , addressExts = addressExts x <> addressExts y
79 instance Monoid Address where
80 mempty = Address{addressSegs = [], addressExts = []}
82 addressFile :: Address -> Sys.FilePath
84 List.intercalate "." $
85 encodePath (addressSegs addr)
86 : (Text.unpack . encodePathSegment <$> addressExts addr)