4

代わりにcheckMに次のタイプを与えることは可能でしょうか?

checkM :: RenderMessage master msg => 
          (a -> GHandler sub master (Either msg b)) -> 
          Field sub master a -> Field sub master b

その理由は次のとおりです。

ユーザー名を尋ねるフォームがあります。checkMを使用して、入力したユーザーが存在するかどうかをデータベースですぐに検索します。

userField = checkM userexists textField
userexists input = do
  mbuser <- runDB $ getBy $ UniqueName input
  return $ case mbuser of
    Nothing  -> Left ("This user does not exist!" :: Text)
    (Just (Entity uid _)) -> Right input 
    -- I would like to write "return Right uid" above!

ただし、return :: Textしか返すことができないため、フォームがユーザー入力を受け入れた直後に、同じ名前の別のデータベースルックアップを実行して、そのユーザーのデータベースキーを取得する必要があります。これは、私が本当に望んでいたことです。

(この例は大幅に簡略化されています。基本的に、一連の異なるユーザー入力のデータベースキーを取得したいのですが(すべて1つの形式で)、TextFieldsとしてのみ要求できますか?)

4

1 に答える 1

3

型シグネチャがそのように見える理由は、Field:の解析方法とレンダリング方法の2つの側面があるためです。checkMフィールドの解析方法を変更するだけですが、レンダリング関数(fieldView)は変更されません。したがって、値は同じタイプを維持する必要があります。

必要な動作を取得するために私が考えることができる最も簡単な方法は、新しい型の値から古い型の値を取得できる関数を持つことです。そうすれば、新しい値が与えられた場合、その関数をそれに適用して、レンダリングの目的で古い値を取得できます。コードは次のようになります。

checkM' :: RenderMessage master msg
        => (a -> GHandler sub master (Either msg b))
        -> (b -> a)
        -> Field sub master a
        -> Field sub master b
checkM' f inv field = field
    { fieldParse = \ts -> do
        e1 <- fieldParse field ts
        case e1 of
            Left msg -> return $ Left msg
            Right Nothing -> return $ Right Nothing
            Right (Just a) -> fmap (either (Left . SomeMessage) (Right . Just)) $ f a
    , fieldView = \i n a eres req -> fieldView field i n a (fmap inv eres) req
    }

したがって、あなたの場合、最後の行をuserexists次のように変更することで使用できます。

(Just (Entity uid _)) -> Right (input, uid)

そして、次のように定義userFieldします

userField = checkM' userexists fst textField

のような関数checkMをyesod-formに含めるのは理にかなっていると思いますが、うまくいけばもっと良い名前を付けてください;)。

于 2012-06-29T03:14:59.380 に答える