Edit File by line

Deprecated: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in /home/sportsfever/public_html/filemanger/function.php on line 93
/home/sportsfe.../httpdocs/wp-conte.../plugins/wp-file-.../lib/codemirr.../mode/haskell-...
File: index.html
<!doctype html>
[0] Fix | Delete
[1] Fix | Delete
<title>CodeMirror: Haskell-literate mode</title>
[2] Fix | Delete
<meta charset="utf-8"/>
[3] Fix | Delete
<link rel=stylesheet href="../../doc/docs.css">
[4] Fix | Delete
[5] Fix | Delete
<link rel="stylesheet" href="../../lib/codemirror.css">
[6] Fix | Delete
<script src="../../lib/codemirror.js"></script>
[7] Fix | Delete
<script src="haskell-literate.js"></script>
[8] Fix | Delete
<script src="../haskell/haskell.js"></script>
[9] Fix | Delete
<style>.CodeMirror {
[10] Fix | Delete
border-top : 1px solid #DDDDDD;
[11] Fix | Delete
border-bottom : 1px solid #DDDDDD;
[12] Fix | Delete
}</style>
[13] Fix | Delete
<div id=nav>
[14] Fix | Delete
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo
[15] Fix | Delete
src="../../doc/logo.png"></a>
[16] Fix | Delete
[17] Fix | Delete
<ul>
[18] Fix | Delete
<li><a href="../../index.html">Home</a>
[19] Fix | Delete
<li><a href="../../doc/manual.html">Manual</a>
[20] Fix | Delete
<li><a href="https://github.com/codemirror/codemirror">Code</a>
[21] Fix | Delete
</ul>
[22] Fix | Delete
<ul>
[23] Fix | Delete
<li><a href="../index.html">Language modes</a>
[24] Fix | Delete
<li><a class=active href="#">Haskell-literate</a>
[25] Fix | Delete
</ul>
[26] Fix | Delete
</div>
[27] Fix | Delete
[28] Fix | Delete
<article>
[29] Fix | Delete
<h2>Haskell literate mode</h2>
[30] Fix | Delete
<form>
[31] Fix | Delete
<textarea id="code" name="code">
[32] Fix | Delete
> {-# LANGUAGE OverloadedStrings #-}
[33] Fix | Delete
> {-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
[34] Fix | Delete
> import Control.Applicative ((<$>), (<*>))
[35] Fix | Delete
> import Data.Maybe (isJust)
[36] Fix | Delete
[37] Fix | Delete
> import Data.Text (Text)
[38] Fix | Delete
> import Text.Blaze ((!))
[39] Fix | Delete
> import qualified Data.Text as T
[40] Fix | Delete
> import qualified Happstack.Server as Happstack
[41] Fix | Delete
> import qualified Text.Blaze.Html5 as H
[42] Fix | Delete
> import qualified Text.Blaze.Html5.Attributes as A
[43] Fix | Delete
[44] Fix | Delete
> import Text.Digestive
[45] Fix | Delete
> import Text.Digestive.Blaze.Html5
[46] Fix | Delete
> import Text.Digestive.Happstack
[47] Fix | Delete
> import Text.Digestive.Util
[48] Fix | Delete
[49] Fix | Delete
Simple forms and validation
[50] Fix | Delete
---------------------------
[51] Fix | Delete
[52] Fix | Delete
Let's start by creating a very simple datatype to represent a user:
[53] Fix | Delete
[54] Fix | Delete
> data User = User
[55] Fix | Delete
> { userName :: Text
[56] Fix | Delete
> , userMail :: Text
[57] Fix | Delete
> } deriving (Show)
[58] Fix | Delete
[59] Fix | Delete
And dive in immediately to create a `Form` for a user. The `Form v m a` type
[60] Fix | Delete
has three parameters:
[61] Fix | Delete
[62] Fix | Delete
- `v`: the type for messages and errors (usually a `String`-like type, `Text` in
[63] Fix | Delete
this case);
[64] Fix | Delete
- `m`: the monad we are operating in, not specified here;
[65] Fix | Delete
- `a`: the return type of the `Form`, in this case, this is obviously `User`.
[66] Fix | Delete
[67] Fix | Delete
> userForm :: Monad m => Form Text m User
[68] Fix | Delete
[69] Fix | Delete
We create forms by using the `Applicative` interface. A few form types are
[70] Fix | Delete
provided in the `Text.Digestive.Form` module, such as `text`, `string`,
[71] Fix | Delete
`bool`...
[72] Fix | Delete
[73] Fix | Delete
In the `digestive-functors` library, the developer is required to label each
[74] Fix | Delete
field using the `.:` operator. This might look like a bit of a burden, but it
[75] Fix | Delete
allows you to do some really useful stuff, like separating the `Form` from the
[76] Fix | Delete
actual HTML layout.
[77] Fix | Delete
[78] Fix | Delete
> userForm = User
[79] Fix | Delete
> <$> "name" .: text Nothing
[80] Fix | Delete
> <*> "mail" .: check "Not a valid email address" checkEmail (text Nothing)
[81] Fix | Delete
[82] Fix | Delete
The `check` function enables you to validate the result of a form. For example,
[83] Fix | Delete
we can validate the email address with a really naive `checkEmail` function.
[84] Fix | Delete
[85] Fix | Delete
> checkEmail :: Text -> Bool
[86] Fix | Delete
> checkEmail = isJust . T.find (== '@')
[87] Fix | Delete
[88] Fix | Delete
More validation
[89] Fix | Delete
---------------
[90] Fix | Delete
[91] Fix | Delete
For our example, we also want descriptions of Haskell libraries, and in order to
[92] Fix | Delete
do that, we need package versions...
[93] Fix | Delete
[94] Fix | Delete
> type Version = [Int]
[95] Fix | Delete
[96] Fix | Delete
We want to let the user input a version number such as `0.1.0.0`. This means we
[97] Fix | Delete
need to validate if the input `Text` is of this form, and then we need to parse
[98] Fix | Delete
it to a `Version` type. Fortunately, we can do this in a single function:
[99] Fix | Delete
`validate` allows conversion between values, which can optionally fail.
[100] Fix | Delete
[101] Fix | Delete
`readMaybe :: Read a => String -> Maybe a` is a utility function imported from
[102] Fix | Delete
`Text.Digestive.Util`.
[103] Fix | Delete
[104] Fix | Delete
> validateVersion :: Text -> Result Text Version
[105] Fix | Delete
> validateVersion = maybe (Error "Cannot parse version") Success .
[106] Fix | Delete
> mapM (readMaybe . T.unpack) . T.split (== '.')
[107] Fix | Delete
[108] Fix | Delete
A quick test in GHCi:
[109] Fix | Delete
[110] Fix | Delete
ghci> validateVersion (T.pack "0.3.2.1")
[111] Fix | Delete
Success [0,3,2,1]
[112] Fix | Delete
ghci> validateVersion (T.pack "0.oops")
[113] Fix | Delete
Error "Cannot parse version"
[114] Fix | Delete
[115] Fix | Delete
It works! This means we can now easily add a `Package` type and a `Form` for it:
[116] Fix | Delete
[117] Fix | Delete
> data Category = Web | Text | Math
[118] Fix | Delete
> deriving (Bounded, Enum, Eq, Show)
[119] Fix | Delete
[120] Fix | Delete
> data Package = Package Text Version Category
[121] Fix | Delete
> deriving (Show)
[122] Fix | Delete
[123] Fix | Delete
> packageForm :: Monad m => Form Text m Package
[124] Fix | Delete
> packageForm = Package
[125] Fix | Delete
> <$> "name" .: text Nothing
[126] Fix | Delete
> <*> "version" .: validate validateVersion (text (Just "0.0.0.1"))
[127] Fix | Delete
> <*> "category" .: choice categories Nothing
[128] Fix | Delete
> where
[129] Fix | Delete
> categories = [(x, T.pack (show x)) | x <- [minBound .. maxBound]]
[130] Fix | Delete
[131] Fix | Delete
Composing forms
[132] Fix | Delete
---------------
[133] Fix | Delete
[134] Fix | Delete
A release has an author and a package. Let's use this to illustrate the
[135] Fix | Delete
composability of the digestive-functors library: we can reuse the forms we have
[136] Fix | Delete
written earlier on.
[137] Fix | Delete
[138] Fix | Delete
> data Release = Release User Package
[139] Fix | Delete
> deriving (Show)
[140] Fix | Delete
[141] Fix | Delete
> releaseForm :: Monad m => Form Text m Release
[142] Fix | Delete
> releaseForm = Release
[143] Fix | Delete
> <$> "author" .: userForm
[144] Fix | Delete
> <*> "package" .: packageForm
[145] Fix | Delete
[146] Fix | Delete
Views
[147] Fix | Delete
-----
[148] Fix | Delete
[149] Fix | Delete
As mentioned before, one of the advantages of using digestive-functors is
[150] Fix | Delete
separation of forms and their actual HTML layout. In order to do this, we have
[151] Fix | Delete
another type, `View`.
[152] Fix | Delete
[153] Fix | Delete
We can get a `View` from a `Form` by supplying input. A `View` contains more
[154] Fix | Delete
information than a `Form`, it has:
[155] Fix | Delete
[156] Fix | Delete
- the original form;
[157] Fix | Delete
- the input given by the user;
[158] Fix | Delete
- any errors that have occurred.
[159] Fix | Delete
[160] Fix | Delete
It is this view that we convert to HTML. For this tutorial, we use the
[161] Fix | Delete
[blaze-html] library, and some helpers from the `digestive-functors-blaze`
[162] Fix | Delete
library.
[163] Fix | Delete
[164] Fix | Delete
[blaze-html]: http://jaspervdj.be/blaze/
[165] Fix | Delete
[166] Fix | Delete
Let's write a view for the `User` form. As you can see, we here refer to the
[167] Fix | Delete
different fields in the `userForm`. The `errorList` will generate a list of
[168] Fix | Delete
errors for the `"mail"` field.
[169] Fix | Delete
[170] Fix | Delete
> userView :: View H.Html -> H.Html
[171] Fix | Delete
> userView view = do
[172] Fix | Delete
> label "name" view "Name: "
[173] Fix | Delete
> inputText "name" view
[174] Fix | Delete
> H.br
[175] Fix | Delete
>
[176] Fix | Delete
> errorList "mail" view
[177] Fix | Delete
> label "mail" view "Email address: "
[178] Fix | Delete
> inputText "mail" view
[179] Fix | Delete
> H.br
[180] Fix | Delete
[181] Fix | Delete
Like forms, views are also composable: let's illustrate that by adding a view
[182] Fix | Delete
for the `releaseForm`, in which we reuse `userView`. In order to do this, we
[183] Fix | Delete
take only the parts relevant to the author from the view by using `subView`. We
[184] Fix | Delete
can then pass the resulting view to our own `userView`.
[185] Fix | Delete
We have no special view code for `Package`, so we can just add that to
[186] Fix | Delete
`releaseView` as well. `childErrorList` will generate a list of errors for each
[187] Fix | Delete
child of the specified form. In this case, this means a list of errors from
[188] Fix | Delete
`"package.name"` and `"package.version"`. Note how we use `foo.bar` to refer to
[189] Fix | Delete
nested forms.
[190] Fix | Delete
[191] Fix | Delete
> releaseView :: View H.Html -> H.Html
[192] Fix | Delete
> releaseView view = do
[193] Fix | Delete
> H.h2 "Author"
[194] Fix | Delete
> userView $ subView "author" view
[195] Fix | Delete
>
[196] Fix | Delete
> H.h2 "Package"
[197] Fix | Delete
> childErrorList "package" view
[198] Fix | Delete
>
[199] Fix | Delete
> label "package.name" view "Name: "
[200] Fix | Delete
> inputText "package.name" view
[201] Fix | Delete
> H.br
[202] Fix | Delete
>
[203] Fix | Delete
> label "package.version" view "Version: "
[204] Fix | Delete
> inputText "package.version" view
[205] Fix | Delete
> H.br
[206] Fix | Delete
>
[207] Fix | Delete
> label "package.category" view "Category: "
[208] Fix | Delete
> inputSelect "package.category" view
[209] Fix | Delete
> H.br
[210] Fix | Delete
[211] Fix | Delete
The attentive reader might have wondered what the type parameter for `View` is:
[212] Fix | Delete
it is the `String`-like type used for e.g. error messages.
[213] Fix | Delete
But wait! We have
[214] Fix | Delete
releaseForm :: Monad m => Form Text m Release
[215] Fix | Delete
releaseView :: View H.Html -> H.Html
[216] Fix | Delete
... doesn't this mean that we need a `View Text` rather than a `View Html`? The
[217] Fix | Delete
answer is yes -- but having `View Html` allows us to write these views more
[218] Fix | Delete
easily with the `digestive-functors-blaze` library. Fortunately, we will be able
[219] Fix | Delete
to fix this using the `Functor` instance of `View`.
[220] Fix | Delete
fmap :: Monad m => (v -> w) -> View v -> View w
[221] Fix | Delete
A backend
[222] Fix | Delete
---------
[223] Fix | Delete
To finish this tutorial, we need to be able to actually run this code. We need
[224] Fix | Delete
an HTTP server for that, and we use [Happstack] for this tutorial. The
[225] Fix | Delete
`digestive-functors-happstack` library gives about everything we need for this.
[226] Fix | Delete
[Happstack]: http://happstack.com/
[227] Fix | Delete
[228] Fix | Delete
> site :: Happstack.ServerPart Happstack.Response
[229] Fix | Delete
> site = do
[230] Fix | Delete
> Happstack.decodeBody $ Happstack.defaultBodyPolicy "/tmp" 4096 4096 4096
[231] Fix | Delete
> r <- runForm "test" releaseForm
[232] Fix | Delete
> case r of
[233] Fix | Delete
> (view, Nothing) -> do
[234] Fix | Delete
> let view' = fmap H.toHtml view
[235] Fix | Delete
> Happstack.ok $ Happstack.toResponse $
[236] Fix | Delete
> template $
[237] Fix | Delete
> form view' "/" $ do
[238] Fix | Delete
> releaseView view'
[239] Fix | Delete
> H.br
[240] Fix | Delete
> inputSubmit "Submit"
[241] Fix | Delete
> (_, Just release) -> Happstack.ok $ Happstack.toResponse $
[242] Fix | Delete
> template $ do
[243] Fix | Delete
> css
[244] Fix | Delete
> H.h1 "Release received"
[245] Fix | Delete
> H.p $ H.toHtml $ show release
[246] Fix | Delete
>
[247] Fix | Delete
> main :: IO ()
[248] Fix | Delete
> main = Happstack.simpleHTTP Happstack.nullConf site
[249] Fix | Delete
[250] Fix | Delete
Utilities
[251] Fix | Delete
---------
[252] Fix | Delete
[253] Fix | Delete
> template :: H.Html -> H.Html
[254] Fix | Delete
> template body = H.docTypeHtml $ do
[255] Fix | Delete
> H.head $ do
[256] Fix | Delete
> H.title "digestive-functors tutorial"
[257] Fix | Delete
> css
[258] Fix | Delete
> H.body body
[259] Fix | Delete
> css :: H.Html
[260] Fix | Delete
> css = H.style ! A.type_ "text/css" $ do
[261] Fix | Delete
> "label {width: 130px; float: left; clear: both}"
[262] Fix | Delete
> "ul.digestive-functors-error-list {"
[263] Fix | Delete
> " color: red;"
[264] Fix | Delete
> " list-style-type: none;"
[265] Fix | Delete
> " padding-left: 0px;"
[266] Fix | Delete
> "}"
[267] Fix | Delete
</textarea>
[268] Fix | Delete
</form>
[269] Fix | Delete
[270] Fix | Delete
<p><strong>MIME types
[271] Fix | Delete
defined:</strong> <code>text/x-literate-haskell</code>.</p>
[272] Fix | Delete
[273] Fix | Delete
<p>Parser configuration parameters recognized: <code>base</code> to
[274] Fix | Delete
set the base mode (defaults to <code>"haskell"</code>).</p>
[275] Fix | Delete
[276] Fix | Delete
<script>
[277] Fix | Delete
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "haskell-literate"});
[278] Fix | Delete
</script>
[279] Fix | Delete
[280] Fix | Delete
</article>
[281] Fix | Delete
[282] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function