mirror of
https://github.com/qfpl/applied-fp-course.git
synced 2024-11-23 03:44:45 +03:00
Updated and shuffled.
Rearranged some of Level01/02 to give a bit more of a hint as to the flow of the questions. Added more helpful text to level02/Types.sh
This commit is contained in:
parent
d901dedf24
commit
c5264cef02
@ -6,28 +6,37 @@ import Network.Wai.Handler.Warp (run)
|
||||
|
||||
import Network.HTTP.Types (status200)
|
||||
|
||||
{-|
|
||||
This is about as basic as it gets.
|
||||
-}
|
||||
-- We keep this main function here as it is useful to build your application as
|
||||
-- a library. The reasoning behind this is that when you come to do your
|
||||
-- testing, you'll be able to import the entire application as a library without
|
||||
-- needing to worry about any initialisation code you've buried in your
|
||||
-- executeable Main.sh.
|
||||
runApp :: IO ()
|
||||
runApp = run 3000 app
|
||||
|
||||
{-|
|
||||
Our "application" will simply respond to ALL incoming requests with a 200 status
|
||||
code response and the message "Hello, World!"
|
||||
|
||||
The Application type from Wai is a type synonym for the follwing type:
|
||||
|
||||
:: Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
|
||||
|
||||
So the first argument to our function below is the incoming Request, which we
|
||||
disregard using `_`. The next input is the callback function that signals when
|
||||
our request is complete.
|
||||
|
||||
This callback function is to signal to the Wai framework and we've completed our
|
||||
part and it's free to close any resources it had and send the response.
|
||||
-}
|
||||
-- Our "application" will simply respond to ALL incoming requests with a 200
|
||||
-- status code response and the message "Hello, World!"
|
||||
--
|
||||
-- The Application type from Wai is a type synonym for the follwing type:
|
||||
--
|
||||
-- :: Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
|
||||
--
|
||||
-- So the first argument to our function below is the incoming Request, which we
|
||||
-- disregard using `_`. The next input is the callback function that signals
|
||||
-- when our request is complete.
|
||||
--
|
||||
-- This callback function is to signal to the Wai framework and we've completed
|
||||
-- our part and it's free to close any resources it had and send the response.
|
||||
--
|
||||
-- This exercise is about tracking down the right documentation to find out what
|
||||
-- you need to use to build this function. The types can guide you to some
|
||||
-- extent, but you will have to be able to use the library documentation to find
|
||||
-- what you need.
|
||||
--
|
||||
-- We've used the non-synonym version of the `Application` type below.
|
||||
app
|
||||
:: Application
|
||||
app _ cb =
|
||||
:: Request
|
||||
-> (Response -> IO ResponseReceived)
|
||||
-> IO ResponseReceived
|
||||
app rq cb =
|
||||
error "Application not implemented"
|
||||
|
@ -16,6 +16,11 @@ import Data.Text.Encoding (decodeUtf8)
|
||||
|
||||
import FirstApp.Types
|
||||
|
||||
|
||||
-- |------------------------------------------------------|
|
||||
-- | Don't start here, go straight to FirstApp.Types! :) |
|
||||
-- |------------------------------------------------------|
|
||||
|
||||
runApp :: IO ()
|
||||
runApp = run 3000 app
|
||||
|
||||
@ -47,17 +52,6 @@ resp400 =
|
||||
error "resp400 not implemented"
|
||||
-- |
|
||||
|
||||
{-|
|
||||
How can we use the types to make this better?
|
||||
|
||||
We need a way to go from the pathInfo and requestMethod to a Request type
|
||||
that matches our current specification.
|
||||
-}
|
||||
app
|
||||
:: Application
|
||||
app rq cb =
|
||||
error "app not implemented"
|
||||
|
||||
{-|
|
||||
Lets use our RqTypes to write a function that will take the input from the
|
||||
Wai library and turn it into something our application cares about.
|
||||
@ -98,7 +92,6 @@ mkListRequest
|
||||
mkListRequest =
|
||||
error "mkListRequest not implemented"
|
||||
|
||||
|
||||
{-|
|
||||
HALP
|
||||
|
||||
@ -138,3 +131,10 @@ handleRequest
|
||||
-> Either Error Response
|
||||
handleRequest _ =
|
||||
error "handleRequest not implemented"
|
||||
|
||||
-- Reimplement our `app` function using the new functions and the RqTypes as a
|
||||
-- guide.
|
||||
app
|
||||
:: Application
|
||||
app rq cb =
|
||||
error "app not reimplemented"
|
||||
|
@ -4,17 +4,58 @@ module FirstApp.Types where
|
||||
import Data.ByteString (ByteString)
|
||||
import Data.Text (Text)
|
||||
|
||||
{-|
|
||||
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.
|
||||
-- Working through the specification for our application, what are the
|
||||
-- types of requests we're going to handle?
|
||||
|
||||
The type system will check it for you, and the compiler will eliminate the cost
|
||||
once it has passed.
|
||||
-}
|
||||
-- We have to be able to:
|
||||
-- - Comment on a given topic
|
||||
-- - View a topic and its comments
|
||||
-- - List the current topics
|
||||
|
||||
-- To that end, we will create the following types:
|
||||
|
||||
-- AddRq : Which needs to the target topic, and the body of the comment.
|
||||
-- ViewRq : Which needs the topic being requested.
|
||||
-- ListRq : Which lists all of the current topics.
|
||||
data RqType
|
||||
|
||||
-- Not everything goes according to plan, but it's important that our
|
||||
-- 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.
|
||||
data Error
|
||||
|
||||
-- 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
|
||||
|
||||
-- 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.
|
||||
|
||||
-- Having specialised constructor functions for the newtypes allows you to set
|
||||
-- restrictions for your newtype.
|
||||
|
||||
-- Write two `newtype` definitions for `Topic` and `CommentText` that wrap a
|
||||
-- `Text` value
|
||||
|
||||
-- Topic
|
||||
--
|
||||
|
||||
-- Comment
|
||||
--
|
||||
|
||||
-- |
|
||||
|
||||
-- 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.
|
||||
mkTopic
|
||||
:: Text
|
||||
-> Either Error Topic
|
||||
@ -27,38 +68,8 @@ mkCommentText
|
||||
mkCommentText =
|
||||
error "mkCommentText not implemented"
|
||||
|
||||
{-|
|
||||
Working through the specification for our application, what are the
|
||||
types of requests we're going to handle?
|
||||
|
||||
Remember that we have to be able to:
|
||||
- Comment on a given topic
|
||||
- View a topic and its comments
|
||||
- List the current topics
|
||||
|
||||
To that end, we will create the following types:
|
||||
|
||||
AddRq : Which needs to the target topic, and the body of the comment.
|
||||
|
||||
ViewRq : Which needs the topic being requested.
|
||||
|
||||
ListRq : Which lists all of the current topics.
|
||||
-}
|
||||
data RqType
|
||||
|
||||
{-|
|
||||
Not everything goes according to plan, but it's important that our
|
||||
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.
|
||||
-}
|
||||
data Error
|
||||
|
||||
-- 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
|
||||
-- After you've implemented these functions, adjust the export list in the
|
||||
-- module declaration so your constructor functions cannot be bypassed.
|
||||
|
||||
-- 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
|
||||
|
Loading…
Reference in New Issue
Block a user