1
1
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:
Sean Chalmers 2017-08-24 11:23:26 +10:00
parent d901dedf24
commit c5264cef02
3 changed files with 91 additions and 71 deletions

View File

@ -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"

View File

@ -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"

View File

@ -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