1
1
mirror of https://github.com/qfpl/applied-fp-course.git synced 2024-11-23 03:44:45 +03:00

Restructured the Types.hs a bit to help with flow

This commit is contained in:
Sean Chalmers 2017-08-24 11:53:52 +10:00
parent c5264cef02
commit e491acb26e
2 changed files with 44 additions and 42 deletions

View File

@ -17,9 +17,9 @@ import Data.Text.Encoding (decodeUtf8)
import FirstApp.Types
-- |------------------------------------------------------|
-- | Don't start here, go straight to FirstApp.Types! :) |
-- |------------------------------------------------------|
-- ---------------------------------------------|
-- Don't start here, go to FirstApp.Types! :) |
-- ---------------------------------------------|
runApp :: IO ()
runApp = run 3000 app
@ -65,6 +65,7 @@ mkRequest rq =
-- These helpers will take the raw request information and turn it into
-- one of our data types. This means we draw a line about where the unruly outside
-- world must end, and where the well-typed world of our application begins.
mkAddRequest
:: Text
-> LBS.ByteString
@ -75,25 +76,27 @@ mkAddRequest ti c =
-- This has other benefits, we're able isolate our validation requirements into the
-- smallest chunks we can manage. This allows for fantastic reuse and it also means
-- that validation is not spread across the application. It is kept at the borders.
mkViewRequest
:: Text
-> Either Error RqType
mkViewRequest =
error "mkViewRequest not implemented"
-- Even thought it may seem trivial or even pointless to write functions such as these
-- it allows for much greater consistency across the application.
-- These are straight forward data constructors, but by doing it this way we don't
-- have any snowflakes littered about the code. It also enhances our ability to
-- spot larger patterns in our application, which are opportunities for abstraction.
-- Even though it may seem too trivial or even pointless to write functions such
-- as these it allows for much greater consistency across the application.
--
-- Some of these are straight forward data constructors, but by doing it this
-- way we don't have any snowflakes littered about the code. It also enhances
-- our ability to spot larger patterns in our application, which are
-- opportunities for abstraction.
mkListRequest
:: Either Error RqType
mkListRequest =
error "mkListRequest not implemented"
{-|
HALP
HALP - wording - is it useful?
Alternative type sig:
Either Error a
@ -112,20 +115,17 @@ mkErrorResponse
mkErrorResponse _ =
error "mkErrorResponse not implemented"
{-|
We'll stub these for now as the general structure and the process of reaching
this stage is the more important lesson here.
Notice how we're only accepting our predefined request types that have the required
information already validated and prepared for use in the handling of the request.
If we find that we need more information to handle a request, or we have a new
type of request that we'd like to handle then we simply update the RqType structure
and the compiler will let us know the affected portions of our application.
Reduction of concerns such that each section of the application only deals with
a small piece is one of the benefits of developing in this way.
-}
-- Notice how we're only accepting our predefined request types that have the
-- required information already validated and prepared for use in the handling
-- of the request.
--
-- If we find that we need more information to handle a request, or we have a
-- new type of request that we'd like to handle then we simply update the RqType
-- structure and the compiler will let us know the affected portions of our
-- application.
--
-- Reduction of concerns such that each section of the application only deals
-- with a small piece is one of the benefits of developing in this way.
handleRequest
:: RqType
-> Either Error Response

View File

@ -23,23 +23,33 @@ data RqType
-- types reflect when errors can be introduced into our program. Additionally
-- it's useful to be able to be descriptive about what went wrong.
-- So lets think about some of the basic things that can wrong with our
-- program and create some values to represent that.
-- Think about some of the basic things that can wrong with our Requests and
-- building the RqTypes, and create some values to represent that.
data Error
-- For now we don't need to worry about things like malformed requests or
-- invalid headers etc.
-- Provide a type to list our response content types so we don't try to
-- do the wrong thing with what we meant to be used as text/JSON etc.
data ContentType
--
-- The ContentType description for a header doesn't match our data definition
-- so we write a little helper function to pattern match on our ContentType
-- value and provide the correct header value.
renderContentType
:: ContentType
-> ByteString
renderContentType =
error "renderContentType not implemented"
-- In Haskell the `newtype` comes with zero runtime cost. It is purely used for
-- typechecking. So when you have a bare 'primitive' value, like an Int, String, or
-- even [a], you can wrap it up in a `newtype` for clarity.
-- The type system will check it for you, and the compiler will eliminate the cost
-- once it has passed.
-- The type system will check it for you, and the compiler will eliminate the cost.
-- Having specialised constructor functions for the newtypes allows you to set
-- restrictions for your newtype.
-- extra restrictions for your newtype.
-- Write two `newtype` definitions for `Topic` and `CommentText` that wrap a
-- `Text` value
@ -52,10 +62,9 @@ data ContentType
-- |
-- An additional benefit of `newtype` is that we can choose to not export the
-- constructor and provide a function of our own. In our case, we're not
-- interested in empty `Text` values so we can eliminate them and immediately
-- report an error.
-- A benefit of `newtype` is that we can choose to *not* export the constructor
-- and provide a function of our own. In our case, we're not interested in empty
-- `Text` values so we can eliminate them and immediately report an error.
mkTopic
:: Text
-> Either Error Topic
@ -69,13 +78,6 @@ mkCommentText =
error "mkCommentText not implemented"
-- After you've implemented these functions, adjust the export list in the
-- module declaration so your constructor functions cannot be bypassed.
-- module declaration so your constructor functions cannot be bypassed. Also
-- export the functions that let you access the inner value of the newtype.
-- The ContentType description for a header doesn't match our data definition
-- so we write a little helper function to pattern match on our ContentType
-- value and provide the correct header value.
renderContentType
:: ContentType
-> ByteString
renderContentType =
error "renderContentType not implemented"