0

掘り下げているData.BSON.Document構造のグループがあり、それぞれをユーザーデータ構造に変換しています(ユーザーを定義しました)。解凍を行う関数は非常に簡単です。

docToUser :: Document -> Either String User
docToUser u = do
    name <- look "name" u >>= \(String t) -> return $ unpack t
    email <- look "email" u >>= \(String t) -> return $ unpack t
    token <- look "auth" u >>= \(String t) -> return $ unpack t
    Right $ User name email token

ただし、キャッチは、どちらのコンテキストでも実際にはエラーが発生していないように見えることです。実行例を次に示します。

*DB> docToUser ["name" =: "Savanni", "email" =: "savanni@nowhere.com", "auth" =: "random_token"]
Right (User {name = "Savanni", email = "savanni@nowhere.com", token = "random_token"})
*DB> docToUser ["name" =: "Savanni", "email" =: "savanni@nowhere.com", "a" =: "random_token"]
*** Exception: expected "auth" in [ name: "Savanni", email: "savanni@nowhere.com", a: "random_token"]

したがって、最初の実行では、Rightコンストラクター内にラップされたユーザーが返されます。2つ目は、などのようなものを期待してLeft "field not found"いましたが、代わりに完全な例外が発生します。どちらかのデータ構造内に格納されたエラーの代わりに、これが発生するのはなぜですか?

4

3 に答える 3

2

lookfailモナディックプリミティブ全体で「見つからない」ことを示します。返品タイプがであるという事実Eitherは関係ありません。do式内でこの失敗を処理することはできません。次のように書く必要があります。

unpackUser u = case (look "name" u, look "email" u, look "auth") of
    (Just (String name), Just (String email), Just (String token)) -> Right $ User (unpack name) (unpack email) (unpack token)
    _ -> Left $ "Missing required fields"
于 2012-11-25T21:23:06.490 に答える
1

ここここ、およびその他の一般的なグーグルから見つけることができる情報に基づいて...どちらかのモナドのインスタンスには実装ありません。fail推測では、Leftではなく例外が発生するのはそのためです。私はこの小さなテストを作成して、次のことを示しました。

eitherMonad :: String -> Either String String
eitherMonad val = do
    if val == "abcd"
        then fail "val is abcd"
        else return "val is something else"

*DB> eitherMonad "abcd"
*** Exception: val is abcd
*DB> eitherMonad "efgh"
Right "val is something else"

一方、fail :: String -> Maybe String実際には何も返しません。私のdocToUser変換を行う正しい方法は、これにもっと似ているように見えます。

docToUser :: Document -> Either String User
docToUser u = do
    let name  = look "name" u :: Maybe Value
    let email = look "email" u :: Maybe Value
    let token = look "auth" u :: Maybe Value
    case (name, email, token) of
        (Just (String n), Just (String e), Just (String t)) -> Right $ User (unpack n) (unpack e) (unpack t)
        (Nothing, _, _) -> Left "username not found"
        (Just (String n), Nothing, _) -> Left "email not found"
        (Just (String n), Just (String e), Nothing) -> Left "auth token not found"
        otherwise -> Left "Something else broke"

特に、どのフィールドが失敗したかを検出して報告する場合は、かなりの改良が必要になると思います。しかし、これは答えにかなり近いようです。

それを考えると、この質問は「標準(どちらか)のモナドインスタンスはありませんか?」と重複していると思います。

于 2012-11-26T03:43:31.087 に答える
0

あなたlookEither文脈であなたを望むなら:

docToUser = do
    String name <- look "name" u
    String email <- look "email" u
    String token <- look "token" u
    return $ User (unpack name) (unpack email) (unpack token)
于 2012-11-26T03:02:43.710 に答える