2

エラーが発生する Haskell Web プロジェクトで状況が発生しましたAmbiguous type variable

関連するコードは

--- Other import statements
import qualified Model as Model

---------- HTTP Handlers
needItem db user itemName = do
  Model.changeItemStatus db user itemName Model.Need
  listItems db user

gotItem db user itemName = do
  Model.changeItemStatus db user itemName Model.Got
  listItems db user

newItem db user itemName comment count = do
  Model.insertItem db user itemName comment count
  listItems db user

listItems db user = do
  lst <- Model.listItems db user
  resOk lst

--- rest of the program

エラーは特にクエリ関数であるinsertItemとについて不平を言っていますchangeItemStatusacid-state

insertItem db name itemName comment count = withAccount db name newItem
  where item = Item { itemName = itemName, itemComment = comment, itemCount = count, itemStatus = Need } 
        newItem account = update' db $ NewItem account item

-- other stuff

changeItemStatus db name itemName status = withAccount db name cItem
  where cItem account = withItem account itemName
                        (\i -> update' db $ ChangeItem account $ i { itemStatus = status})

withAccountデータベースからの戻り値をwithItem処理するのに役立つヘルパー関数です。Maybeそれらは次のように定義されています

withAccount :: MonadIO m => AcidState GoGetDB -> String -> (Account -> a) -> m (Maybe a)
withAccount db name fn = do
  maybeAccount <- query' db $ AccountByName name
  return $ do acct <- maybeAccount
              return $ fn acct

withItem :: Account -> String -> (Item -> a) -> Maybe a
withItem account itemName fn = do
  item <- getOne $ (accountItems account) @= itemName
  return $ fn item

よし、じゃあ。

Happstack クラッシュ コースの AcidState ドキュメントを何度か読みましたが、あまり役に立ちませんでした。彼らは、応答生成関数で直接クエリを使用します。

  • 試してみましたが、iteslfAmbiguous type variableの呼び出しを指していることを除いて、同じエラーが発生しました。query'
  • モデル/コントローラーコード
  • query'呼び出す関数の具体的な戻り値の型が表示されないため、特定の状況には役立ちません(応答を直接生成するため、update'それらの関数は allです)。AcidState DBName -> ServerPart Response

insertItem私は、式の一部を forとchangeItemStatusby usingの型シグネチャをまとめようとしました:tが、すべての試みで、No instance for (MonadIO m1)代わりに悪いエラーであると私が想定しているものを与えてくれました。

私はまだ特に熟達した Haskeller ではないので、他に試してみることができる唯一の方法は、ランダムなreturn $s をその場所にまき散らすことだと思いますが、それでは実際に問題を修正したり、教えたりする可能性が高いとは思えません。私は何でも。

私が実装しようとしている一般的な概念は、「この変更をDBに加えてから、現在のユーザーに関連する要素の(潜在的に変更された)リストを返す」です。

次に何を試すべきか、または具体的にどこが間違っているかについてのヒントはありますか? 私はこれについて完全に間違った方法で考えていますか? この件に関して私が参照できる他のドキュメントはありますか?

PS。上記のすべての関連コードと思われるものを含めましたが、完全なソースを見たい場合は、ここここにあります。

編集: 完全なタイプのエラー

/home/inaimathi/projects/goget/goget.hs:31:3:
    Ambiguous type variable `m2' in the constraint:
      (Control.Monad.IO.Class.MonadIO m2)
        arising from a use of `Model.changeItemStatus'
    Probable fix: add a type signature that fixes these type variable(s)
    In a stmt of a 'do' block:
      Model.changeItemStatus db user itemName Model.Need
    In the expression:
      do { Model.changeItemStatus db user itemName Model.Need;
           listItems db user }
    In an equation for `needItem':
        needItem db user itemName
          = do { Model.changeItemStatus db user itemName Model.Need;
                 listItems db user }

/home/inaimathi/projects/goget/goget.hs:35:3:
    Ambiguous type variable `m1' in the constraint:
      (Control.Monad.IO.Class.MonadIO m1)
        arising from a use of `Model.changeItemStatus'
    Probable fix: add a type signature that fixes these type variable(s)
    In a stmt of a 'do' block:
      Model.changeItemStatus db user itemName Model.Got
    In the expression:
      do { Model.changeItemStatus db user itemName Model.Got;
           listItems db user }
    In an equation for `gotItem':
        gotItem db user itemName
          = do { Model.changeItemStatus db user itemName Model.Got;
                 listItems db user }

/home/inaimathi/projects/goget/goget.hs:39:3:
    Ambiguous type variable `m0' in the constraint:
      (Control.Monad.IO.Class.MonadIO m0)
        arising from a use of `Model.insertItem'
    Probable fix: add a type signature that fixes these type variable(s)
    In a stmt of a 'do' block:
      Model.insertItem db user itemName comment count
    In the expression:
      do { Model.insertItem db user itemName comment count;
           listItems db user }
    In an equation for `newItem':
        newItem db user itemName comment count
          = do { Model.insertItem db user itemName comment count;
                 listItems db user }
4

1 に答える 1

2

関数の型シグネチャを記述して、関数が何をすべきかを把握します。実装を記述する前にそれらを記述してください。そうすれば、型シグネチャを使用できます。また、必要な型をコンパイラが認識している場合は、コンパイラから得られるより適切なエラー メッセージを使用して、実装が [または少なくともあなたがしたいことをしてください。

問題のある子供たちと、彼らが実際に何をしているかを見てみましょう。

acid-state私たちが使用するから

update' :: (UpdateEvent event, MonadIO m) => AcidState (EventState event) -> event -> m (EventResult event)

為に

insertItem db name itemName comment count = withAccount db name newItem
  where item = Item { itemName = itemName, itemComment = comment, itemCount = count, itemStatus = Need } 
        newItem account = update' db $ NewItem account item

では、どのような型が生成されるか見てみましょう。の使用から

withAccount :: MonadIO m => AcidState GoGetDB -> String -> (Account -> a) -> m (Maybe a)

結果には型があることがわかります

m (Maybe a)

一部MonadIO mの の場合、aは の結果の型ですnewItem。今、

newItem account = update' db something

それで

newItem :: MonadIO mio => Account -> mio (EventResult type_of_something)

したがって、結果の型は次のinsertItemようになります

m (Maybe (mio (EventResult type_of_something)))

そして

newItem db user itemName comment count = do
  Model.insertItem db user itemName comment count
  listItems db user

コンパイラはMonadIO mio、2 行目でどちらを使用すべきかを認識していません。したがって、型変数mioはあいまいです。

そこに型変数を指定しても、おそらく期待どおりの結果が得られないことに注意してください。update'実行時にデータベースを更新するアクションを計算するだけでなく、実際に を実行したいと考えています。

の場合insertItem、実際にデータベースを更新する必要がある場合、そのままでwithAccountは役に立ちません。あなたは多分次のようなものを使うことができます

withAccountM :: MonadIO m => AcidState GoGetDB -> String -> (Account -> m a) -> m (Maybe a)
withAccountM db name fn = do
  maybeAccount <- query' db $ AccountByName name
  case maybeAccount of
    Nothing -> return Nothing
    Just acct -> do
         result <- fn acct
         return $ Just result

(テストされていませんが、まだ完全に間違っている可能性があります) 実際にupdate'.

問題と考えられる修正は、 の場合と同様ですchangItemStatus

于 2013-02-06T20:28:30.523 に答える