1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【HaskellでWeb開発入門】「ScottyのActionM」って何?どんな型なの?

Last updated at Posted at 2025-06-05

この記事の目的

  • Haskell の Web フレームワーク Scotty に登場する ActionM の正体を理解する
  • ActionM の使い方を、具体例付きで実感する
  • Haskell で「Webアプリってどう書くの?」という疑問に答える

ScottyのActionMって何?

Haskell の Web開発用フレームワーク Scotty。
そこで登場する型(型コンストラクタ)がActionMです。

一言でいうと、
「Webリクエストに対する処理を書くための“箱(モナド)”」
です。

Webアプリでは、

  • ユーザーからリクエストが来て
  • 処理して
  • レスポンスを返す

という流れがあります。

この「一連の流れ」を書くための場所、それが ActionM です。

※モナドについて
ここでは、厳密な話はしません。正確ではないですが、外部に影響を与えないようにするための箱、のようなイメージを持ってみてください。

どこで出てくる?

よくある例

get "/hello" $ do
  json $ object ["message" .= ("Hello!" :: String)]

ここで do ブロックの中身はすべて ActionM () 型です。
つまり、

  • 「GET /hello」というリクエストに対して
  • 「JSONを返す」というアクションを
  • ActionM の中で実行している

ActionM の中で使える主な関数

関数 用途
param URLのパラメータ取得 param "id"/memos/:id の値を取得
body POSTされたリクエストボディを取得 JSON文字列などを受け取る
json JSONを返す json memo
status HTTPステータスコードを設定 status status404
liftIO IO処理を使う DBアクセスなどで使用

具体例つきで学ぶ

例1: 単純なレスポンスを返す

get "/hello" $ do
  json $ object ["message" .= ("Hello, world!" :: String)]

/hello にアクセスした人に、JSON形式でメッセージを返すだけの処理です。

例2: パラメータ付きのレスポンス

get "/hello/:name" $ do
  name <- param "name"
  json $ object ["message" .= ("Hello, " ++ name ++ "!")]

/hello/Alice にアクセスすると {"message": "Hello, Alice!"} が返ります。

例3: POSTされたデータを受け取って保存

post "/echo" $ do
  b <- body
  text b

リクエストボディをそのまま返すだけのエコーサーバー。

ActionM の裏側 ActionT

Scottyの内部では、ActionM は以下のように定義されています。

type ActionM = ActionT IO

つまり、ActionTによって定義されています。
ActionTの定義を見てみましょう。

-- 簡略版の定義
newtype ActionT m a = ActionT { runActionT :: Request -> m (Response, a) }
  • ActionT は モナド変換子(Monad Transformer) です。
  • 型パラメータ m には、通常 IO などのモナドが入ります。
  • a は「処理の結果として返す値の型」です。
  • Request -> m (Response, a) という関数をラップしています。

つまり、「HTTPリクエストを受け取り、レスポンスを生成するような処理(副作用あり)を表現するモナド」を意味しています。

例えば、ActionT IO Stringならば、IO を使って HTTP リクエストを処理し、最終的に String を返す ActionT モナド、という意味です。

ActionMの定義に戻りましょう。

type ActionM = ActionT IO
  • ActionM は ActionT に IO を固定した型のエイリアス(別名) です。
  • つまり、「IOモナドで動く ActionT」ということです。

IO モナドについて 補足

Haskellは純粋関数型言語なので、「副作用(=外部世界への影響)」は直接書けません。ですがWebアプリでは、

  • ユーザーの入力を受け取る
  • データベースを操作する
  • ファイルを読み書きする

といった副作用は必須です。
そのため、こうした副作用を「安全な箱」で包むのが IO モナドです。

実用:メモの作成処理(POST)

post "/memos" $ do
  b <- body
  case eitherDecode b :: Either String NewMemo of
    Left err -> do
      status status400
      json $ object ["error" .= ("Invalid JSON: " ++ err)]
    Right newMemo -> do
      liftIO $ saveToDB newMemo
      status status201
      json newMemo

  • body でリクエストボディを取り出し
  • eitherDecode で JSON を解析
  • エラーなら 400 を返し
  • 成功したら DB に保存し、201 を返す

という処理を ActionM の中で書いています。

※例として、メモはNewMemo型で管理しています。

補足 getの型は?

get "/hello" $ do
  json $ object ["msg" .= ("Hello!" :: String)]

このgetの型も確認しておきます。

getの型

get :: RoutePattern -> ActionM () -> ScottyM ()

「指定したパスに対して、HTTP GET リクエストが来たときの処理(ActionM)を登録する処理(ScottyM)」です。

RoutePattern型とは?

リクエストの パスにマッチするための「パターン」の型

ActionM ()の()とは?

()は、「何も返さない」ことを表す特別な型です。
Webリクエストに対して何らかの処理を行うけど、処理の結果(値)は外に返さない。副作用だけを行う。

ScottyM ()

これはルーティングを定義する Scottyアプリ全体の設定を構築するためのモナド。
get は「このルーティングを1つ追加する」という副作用的な処理なので、結果は ScottyM ()型になります。

関連記事

https://qiita.com/meta77/items/3e62724bb4a4f4ac9541
https://qiita.com/meta77/items/91e09025338626fa220b
https://qiita.com/meta77/items/6d6bbbc3abc4b7bd8338

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?