4

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 エラーを回避するにはどうすればよいですか?

4

2 に答える 2

-1

コンテキスト内の値、つまり IO (* -> ) と値 ( )を混在させています。値に対して「do」タイプの構文を実行することはできません。簡単な解決策は、unsafePerformIO を使用することです。使用法はコンテキストによって異なります (「安全でない」という言葉に注意してください)。推奨されるアプローチは、最後に IO を持つモナド トランスフォーマー スタックを使用し、次に liftIO を使用して IO アクションを実行することです。

于 2015-04-22T11:23:28.577 に答える