warp、wai、acid-state を使用して Haskell で Web サービスを作成しています。現在、データベースとの対話を必要とする 2 つのハンドラー関数があり、後者は私に問題を引き起こしています。
1 つ目は、登録です。
registerUser :: AcidState UserDatabase -> Maybe (Map.Map String String) -> Response
registerUser db maybeUserMap =
case maybeUserMap of
(Just u) -> let _ = fmap (\id -> update db (StoreUser (toString id) u)) (nextRandom)
in resPlain status200 "User Created."
Nothing -> resPlain status401 "Invalid user JSON."
ご覧のとおりIO
、 で更新を実行することで、応答への感染を回避することができましたlet _ = ..
。
ログイン関数 (現在はユーザー マップのみを返す) では、IO
実際に応答で結果を返す必要があるため、 を避けることはできません。
loginUser :: AcidState UserDatabase -> String -> Response
loginUser db username = do
maybeUserMap <- (query db (FetchUser username))
case maybeUserMap of
(Just u) -> resJSON u
Nothing -> resPlain status401 "Invalid username."
これにより、次のエラーが発生します。
src/Main.hs:40:3:
Couldn't match type ‘IO b0’ with ‘Response’
Expected type: IO (EventResult FetchUser)
-> (EventResult FetchUser -> IO b0) -> Response
Actual type: IO (EventResult FetchUser)
-> (EventResult FetchUser -> IO b0) -> IO b0
In a stmt of a 'do' block:
maybeUserMap <- (query db (FetchUser username))
In the expression:
do { maybeUserMap <- (query db (FetchUser username));
case maybeUserMap of {
(Just u) -> resJSON u
Nothing -> resPlain status401 "Invalid username." } }
In an equation for ‘loginUser’:
loginUser db username
= do { maybeUserMap <- (query db (FetchUser username));
case maybeUserMap of {
(Just u) -> resJSON u
Nothing -> resPlain status401 "Invalid username." } }
src/Main.hs:42:17:
Couldn't match expected type ‘IO b0’ with actual type ‘Response’
In the expression: resJSON u
In a case alternative: (Just u) -> resJSON u
src/Main.hs:43:17:
Couldn't match expected type ‘IO b0’ with actual type ‘Response’
In the expression: resPlain status401 "Invalid username."
In a case alternative:
Nothing -> resPlain status401 "Invalid username."
エラーは、値を返す db クエリが原因であると考えられIO
ます。私が最初に考えたのはResponse
、型シグネチャを に変更することでしたIO Response
が、最上位の関数は、Response
ではなく が必要であると不平を言いましたIO Response
。
同様に、次のように書きたいとregisterUser
思います。
registerUser :: AcidState UserDatabase -> Maybe (Map.Map String String) -> Response
registerUser db maybeUserMap =
case maybeUserMap of
(Just u) -> do uuid <- (nextRandom)
update db (StoreUser (toString uuid) u)
resPlain status200 (toString uuid)
Nothing -> resPlain status401 "Invalid user JSON."
しかし、これは非常によく似たエラーを引き起こします。
registerUser
完全を期すために、 andを呼び出す関数を次に示しますloginUser
。
authRoutes :: AcidState UserDatabase -> Request -> [Text.Text] -> String -> Response
authRoutes db request path body =
case path of
("register":rest) -> registerUser db (decode (LB.pack body) :: Maybe (Map.Map String String))
("login":rest) -> loginUser db body
("access":rest) -> resPlain status404 "Not implemented."
_ -> resPlain status404 "Not Found."
これらの IO エラーを回避するにはどうすればよいですか?