macOS
$ curl -sSL https://get.haskellstack.org/ | sh
    Windows
下記サイトよりインストーラーをダウンロード
Get Started with Haskell WindowsLinux
$ wget -qO- https://get.haskellstack.org/ | sh
    詳しくは下記サイトを参照
Get started with Haskellよりシンプルな形にするために、プロジェクトを手動で作成します。
$ mkdir spock-web
$ cd spock-web
$ mkdir src
    「spock-web」プロジェクト内に、次の内容の「spock-web.cabal」という ファイルを作ります。
name:                spock-web
version:             0.1.0.0
category:            Web
build-type:          Simple
cabal-version:       >=1.10
executable spock-web
  main-is:            Main.hs
  build-depends:      base >=4.10 && <4.11
                    , Spock
                    , lucid
                    , Spock-lucid
                    , text
  hs-source-dirs:     src
  default-language:   Haskell2010
    
    「spock-web」プロジェクト内の「src」ディレクトリ内に、
    次の内容の「Main.hs」というファイルを作ります。
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Web.Spock
import Web.Spock.Config
import Web.Spock.Lucid (lucid)
import Lucid
import Data.Semigroup ((<>))
import Control.Monad.IO.Class (liftIO)
import Control.Monad (forM_)
import Data.Text (Text)
import Data.IORef
data Note = Note { author :: Text, article :: Text }
newtype ServerState = ServerState { notes :: IORef [Note] }
type Server a = SpockM () () ServerState a
app :: Server ()
app = do
    get root $ do
        database <- getState >>= (liftIO . readIORef . notes)
        lucid $ do
            h3_ "記事"
            ol_ $ forM_ database $ \note -> li_ $ do
                small_ $ toHtml (author note)
                p_ $ small_ $ toHtml (article note)
            small_  "投稿者と記事を入力して投稿ボタンを押してください"
            form_ [method_ "post"] $ do
                label_ $ do
                    "投稿者 "
                    input_ [name_ "author"]
                br_ []
                label_ $ do
                    "記 事 "
                    textarea_ [rows_ "4", cols_ "40",
                        name_ "article"] ""
                    input_ [type_ "submit", value_ "投稿"]   
    post root $ do
        author   <- param' "author"
        article  <- param' "article"
        notesRef <- notes <$> getState
        liftIO $ atomicModifyIORef' notesRef $ \notes ->
            (notes <> [Note author article], ())
        redirect "/"    
main :: IO ()
main = do
    st  <- ServerState <$> newIORef []
    cfg <- defaultSpockCfg () PCNoDatabase st
    runSpock 8080 (spock cfg app)
    ビルド
$ stack init
$ stack build
    初回のビルドは「Spock」の開発環境と実行環境をインストールするため、 非常に時間がかかります。2回目からのビルドはすぐに終わります。
実行
$ stack exec spock-web
Spock is running on port 8080
    
    ブラウザを起動して「https://localhost:8080/」
    へアクセスして、何か入力します。
 
    投稿」ボタンを押すと、次のようになります。
 
    
    終了させるには、 ターミナルに、Controlキーと c と入力します。
    
^C
    デプロイする場合の「Main.hs」は次のようになります。 「spock-web.cabal」に変更はありません。
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Web.Spock
import Web.Spock.Config
import Web.Spock.Lucid (lucid)
import Lucid
import Data.Semigroup ((<>))
import Control.Monad.IO.Class (liftIO)
import Control.Monad (forM_)
import Data.Text (Text)
import Data.IORef
import System.Environment
import Control.Monad
data Note = Note { author :: Text, article :: Text }
newtype ServerState = ServerState { notes :: IORef [Note] }
type Server a = SpockM () () ServerState a
app :: Server ()
app = do
    get root $ do
        database <- getState >>= (liftIO . readIORef . notes)
        lucid $ do
            h3_ "記事"
            ol_ $ forM_ database $ \note -> li_ $ do
                small_ $ toHtml (author note)
                p_ $ small_ $ toHtml (article note)
            small_  "投稿者と記事を入力して投稿ボタンを押してください"
            form_ [method_ "post"] $ do
                label_ $ do
                    "投稿者 "
                    input_ [name_ "author"]
                br_ []
                label_ $ do
                    "記 事 "
                    textarea_ [rows_ "4", cols_ "40",
                        name_ "article"] ""
                    input_ [type_ "submit", value_ "投稿"]   
    post root $ do
        author   <- param' "author"
        article  <- param' "article"
        notesRef <- notes <$> getState
        liftIO $ atomicModifyIORef' notesRef $ \notes ->
            (notes <> [Note author article], ())
        redirect "/"    
main :: IO ()
main = do
    port <- liftM read $ getEnv "PORT"
    st   <- ServerState <$> newIORef []
    cfg  <- defaultSpockCfg () PCNoDatabase st
    runSpock port (spock cfg app)