Figure 1: Arch. overview

Figure 2: Death star
Figure 3: Quasar overview
STM)
Figure 4: Quasar PL Legend
Figure 5: Quasar PL Example
STM lets us do this elegantly!-- Example servant route: "login" :> Header "Authorization" AuthData :> Post '[JSON] AuthResult -- Authentication result data AuthResult = AuthSuccess UserInfo | AuthFailed Reason data AuthData = UserToken ByteString -- Authentication data
POST /login Authorization: <UserAuthData>
AuthResult authUser :: UserAuthData -> AuthResult authUser authData = do something
STM (Software transactional memory)Maybe functorvar int myNullableInt = 10; myNullableInt = null; // this perfectly ok myNullableInt = 20; // also ok // elsewhere in your code (also ok): myNullableInt2 = myNullableInt + 1;
myNullableInt is null and you're adding 1 to it?null may be treated as 0 depending on the whims of your language)null is not a valid value
we have Maybe Int instead of an Int that can randomly disappear on us
data Maybe a = Just a | Nothing
Maybe is a FunctorFunctor?Functor is a mapping between categories (out of scope of this talk)
tl;dr: it lets us do things like:
-- say we have a function: func :: a -> b func = something -- and we have a functor f and a functor value: x :: f a -- the functor typeclass in haskell supplies us with a function called fmap: fmap :: Functor f => (a -> b) -> f a -> f b -- and now we can do this: fmap func x -- which will give us a value :: f b
Now we can do:
-- say we have some value that is a Maybe Int x = Just 10 -- in our previous example, we wanted to add 1 to the int, safely. -- so we can now do: fmap (+1) x -- this will give us: Just 11 -- and what if we had a Nothing? That's fine too: y = Nothing :: Maybe Int fmap (+1) y -- this will give us: Nothing
type SecretSantaAPI = "api" :> "secretsanta" :> -- PUT request that accepts a `UnmatchedHat` payload and returns `Id`, -- both in JSON format ( ReqBody '[JSON] UnmatchedHat :> Put '[JSON] Id -- GET request that accepts an `Id` URL parameter and returns a hat -- if found :<|> Capture "id" Id :> Get '[JSON] (Maybe AnyHat) -- POST request that accepts an `Id` URL parameter and matches its -- hat if it exists :<|> Capture "id" Id :> "match" :> Post '[JSON] (Maybe SantaError) ) -- | The function that actually serves the API defined above. secretSantaServer :: Server SecretSantaAPI secretSantaServer = runServer $ putHat :<|> getHat :<|> matchHatById
GADTs and DataKinds
function required:
addCategoryToBusiness :: Bus -> Cat -> Bus
∀ c.level == level1
data Lvl = L1 | L0 data Cat = Cat { name :: Text, lvl :: Lvl } addCategoryToBusiness :: Bus -> Cat -> Bus addCategoryToBusiness b c | lvl c == L1 = do something | otherwise = do error
addCategoryToBusiness with Cat with L0DataKinds: lift data-types to kinds (kinds ≊ types of types)Lvl to the kinds leveldata CatLvl (lvl :: Lvl) where CatL0 :: Cat -> CatLvl 'L0 CatL1 :: CatLvl 'L0 -- parent cat. -> Cat -- the L1 cat -> CatLvl 'L1 -- thusly: addCategoryToBusiness :: Bus -> CatLvl 'L1 -> Bus -- compile err: addCategoryToBusiness (undefined :: Bus) (undefined :: CatLvl 'L0)
IO monadIO monadIO as possibleSTMSTM monad allows elegant locking and transactionsSTM actions on guarantees of atomicity
Drop to IO:
atomically :: STM a -> IO a
ReaderT patternReaderT patternReader monad Reader r a:r
get the value with
ask :: Reader r r
ReaderT monad transformer ReaderT r m a:Reader capabilities to another monad mReaderT patternReaderT pattern:ReaderT Env IOEnv datatype contains our application valuesTVar (with STM from previous part)
=> Env stores read-only pointer, we modify the value at the pointer
-- | The memory is simply a map of Ids to Hats type Memory = Map.Map Id AnyHat -- | The environment contains a mutable variable to the memory newtype Env = Env { envMemory :: TVar Memory , envName :: String , envHttpManager :: HttpManager } -- | Create an empty environment emptyEnv :: IO Env emptyEnv = do mem <- newTVarIO Map.empty let name = "my app name" mgr <- newHttpManager return $ Env mem name mgr
ReaderT usageputHat :: UnmatchedHat -> ReaderT Env IO Id putHat h = do let anyhat = AnyHat h tvar <- envMemory <$> ask lift . atomically $ stateTVar tvar $ \mem -> let n = Map.size mem in (n, Map.insert n anyhat mem)
Secret Santa API server:
| Name | Editor(s) |
|---|---|
| Haskell IDE Engine | LSP |
| Intero (EOL) | Emacs |
| dante | Emacs |
| ghci | CLI |
| ghcid | CLI |