3

私はYesodに完全に慣れていません(そしてhaskellの経験はあまりありません)。そして、最初のハンドラーを構築しようとしています。デフォルトのパラメーターを使用してアプリをスクラフフォールドし(Yesod 0.9.4.1バージョンを使用しており、スクラフフォールディングでpostgresqlを選択しています)、selectListを使用してテーブルからデータを取得しようとしています。モデル構成ファイルで新しいテーブル(Fooと呼びましょう)を定義しました。

    Foo
        xStart Int
        yStart Int

FooIdと他のいくつかのFoo属性のリストを渡したいので、ルートを定義しました。

/foos/#Int/#Int/*FooId FoosReturnR GET

およびハンドラー:

    module Handler.FoosReturn where

    import Import

    selectWindowSize :: Int 
    selectWindowSize = 10000

    getFoosReturnR :: Int -> Int -> [FooId] -> Handler RepPlain
    getFoosReturnR x y withoutIds = do
        foos <- runDB $ selectList [FooId /<-. withoutIds, 
               FooXStart <. x + selectWindowSize,
               FooXStart >=. x - selectWindowSize, 
               FooYStart <. y + selectWindowSize,
               FooYStart >=. y - selectWindowSize] [] 
        return $ RepPlain $ toContent $ show foos

Application.hsにハンドラーをインポートし、それをcabalファイルに追加しました。これを実行しようとすると、FooIdはMultiPieceのインスタンスではないというエラーが表示されますが、インスタンスにしようとすると、 FooIdは型の同義語であり、MultiPieceのインスタンスにはできないというエラー-この問題を解決するにはどうすればよいですか?


編集:ダニエル:ええと、実際にはFooIdが正確に何であるかはわかりません-これは、これまで完全には理解していないYesodの魔法の一部です-テーブル定義から自動的に生成されます-しかし、それはある種の数値です。

MultiPieceの使用方法がわからないため、より単純なソリューションに切り替えて変更しました。

ルート:/foos/#Int/#Int/#String FoosReturnR GET

ハンドラー:[ログも追加]

    module Handler.FoosReturn where

    import Import
    import Data.List.Split
    import qualified Data.Text.Lazy as TL

    selectWindowSize :: Int 
    selectWindowSize = 10000

    getFoosReturnR :: Int -> Int -> String -> Handler RepPlain
    getFoosReturnR x y withoutIds = do
        app <- getYesod
        liftIO $ logLazyText (getLogger app) ("getFoosReturnR('" `TL.append` (TL.pack $ (show x) ++ "', '" ++ (show y) ++ "', '" ++ withoutIds ++ "') "))
        foos <- runDB $ selectList [FooId /<-. (map (\a -> read a :: FooId) $ splitOn "," withoutIds), 
               FooXStart <. x + selectWindowSize,
               FooXStart >=. x - selectWindowSize, 
               FooYStart <. y + selectWindowSize,
               FooYStart >=. y - selectWindowSize] [] 
        return $ RepPlain $ toContent $ show foos

コンパイル中ですが、http:// localhost:3000 /ectors / 1/1 / 1,2を参照すると、次のページのみが表示されます。内部サーバーエラーPrelude.read:解析なし

さて、私はここでFooIdが何であるかを完全には理解していません-数字を含む文字列のリストからFooIdのそのようなリストを作成する方法は?

そしてもちろん、FooIdをMultiPieceのインスタンスにする方法の解決策が最も望まれています。


編集:

ダニエルとsvachalek、あなたの投稿に感謝します-私はあなたの(ダニエルの)解決策を試しましたが、[FooId]が期待されているというエラーを受け取りました(ハンドラー関数宣言のように)が、FooIdタイプが与えられ、これは私を次の解決策に導きます:

    data FooIds = FooIds [FooId] deriving (Show, Read, Eq)

    instance MultiPiece FooIds where
        toMultiPiece (FooIds fooList) = map (Data.Text.pack . show) fooList
        fromMultiPiece texts = 
            if length (filter isNothing listOfMaybeFooId) > 0
                then Nothing
                else Just $ FooIds $ map fromJust listOfMaybeFooId
            where 
                listOfMaybeFooId = map constructMaybeFooId texts
                constructMaybeFooId :: Text -> Maybe FooId
                constructMaybeFooId x = case reads (Data.Text.unpack x) :: [(FooId,String)] of
                        [(foo,_)] -> Just foo
                        _         -> Nothing

もちろん、ルートを次のように変更しました。/foos/#Int/#Int/*FooIds FoosReturnR GET

およびハンドラー:

    getFoosReturnR :: Int -> Int -> FooIds -> Handler RepPlain
    getFoosReturnR coordX coordY (FooIds withoutIds) = do

そして今、コンパイル中や実行時にエラーが発生することはありません。唯一の満足のいくものではないのは、結果が得られるはずのパラメーターを指定しても、結果として常にNotFoundを受け取ることです。どのSQLがデータベースに正確に送信されたかを判別する方法


編集:

これで、「見つかりません」が問題に関連していることがわかり、上記の編集は解決策ではありません-localhost:3000 / foos / 4930000/3360000を参照すると、結果が得られます(ただし、FooIdsは空です) -しかし、localhost:3000 /ectors / 4930000/3360000/1のようなものを追加すると、常に「見つかりません」と表示されます-したがって、まだ機能していません。

4

3 に答える 3

1

問題は解決しました:)

質問の最後の編集の1つから私の実装を使用して、次のようなURLを参照することができますhttp://localhost:3000/foos/4930000/3360000/Key {unKey = PersistInt64 3}/Key {unKey = PersistInt64 4} 。キータイプは読み取りを派生させますが、非常に友好的な(そして期待される)方法ではありません:)

または、fromMultiPieceの実装を次のように変更します。

    instance MultiPiece FooIds where
        toMultiPiece (FooIds fooList) = map (Data.Text.pack . show) fooList
        fromMultiPiece texts = 
            if length (filter isNothing listOfMaybeFooId) > 0
                then Nothing
                else Just $ FooIds $ map fromJust listOfMaybeFooId
            where 
                listOfMaybeFooId = map constructMaybeFooId texts
                constructMaybeFooId :: Text -> Maybe FooId
                constructMaybeFooId x = case TR.decimal x of 
                        Left err -> Nothing 
                        Right (el,_) -> Just $ Key (PersistInt64 el)

次のようなURLを使用します。http://localhost:3000/foos/4930000/3360000/1/2

Yesod Web FrameworkGoogleGroupのDavidMcBrideに感謝します


編集:上記のソリューションには、PersistInt64タイプを使用するという1つの欠点しかありませんでしたが、このような実装の詳細を使用することはお勧めできませんが、次のようfromPersistValuetoPersistValue関数を使用して修復できます。Database.Persist

    instance MultiPiece FooIds where
        toMultiPiece (FooIds fooList) = map (persistValuetoText . unKey) fooList
            where
                persistValuetoText x = case fromPersistValue x of
                    Left _ -> Data.Text.pack "" 
                    Right val -> Data.Text.pack $ show (val::Int) 
        fromMultiPiece texts = 
            if length (filter isNothing listOfMaybeFooId) > 0
                then Nothing
                else Just $ FooIds $ map fromJust listOfMaybeFooId
            where 
                listOfMaybeFooId = map constructMaybeFooId texts
                constructMaybeFooId :: Text -> Maybe FooId
                constructMaybeFooId x = case TR.decimal x of 
                        Left _ -> Nothing 
                        Right (el,_) -> Just $ Key (toPersistValue (el :: Int))

繰り返しになりますが、これについてもDavid McBrideに感謝します!

于 2012-02-03T17:28:07.437 に答える
1

私が助けてくれたらいいのにと思いますが、私が知る限り、yesodはWebアプリケーションと関係があるので、実際にそれを見たことがありません。だから私は空中で刺すことができます、多分私は何かを打つことができます。

Hayooは

class MultiPiece s where
    fromMultiPiece :: [Text] -> Maybe s
    toMultiPiece :: s -> [Text]

Yesod.Dispatch。インスタンスとおそらくインスタンスFooIdがあるように見えるので、試してみることができますReadShow

{-# LANGUAGE TypeSynonymInstances #-}
-- maybe also FlexibleInstances

instance MultiPiece FooId where
    toMultiPiece foo = [Text.pack $ show foo]
    fromMultiPiece texts =
        case reads (unpack $ Text.concat texts) :: [(FooId,String)] of
          [(foo,_)] -> Just foo
          _         -> Nothing

それが正しいかどうかわからないので、コメントとして投稿したと思いますが、長すぎてコメントの書式があまりありません。それが役に立たない場合、私はそれを削除して、あなたの質問が答えを持っていないのにすでに答えを持っているという印象を与えないようにします。

于 2012-02-02T17:35:56.213 に答える
0

私もYesodにかなり慣れていないので、.cabalファイルのghc-optionsに-XTypeSynonymInstancesを追加して追加しました。これまでのところ、作業がずっと楽になりました。これがこの特定の問題に対する最も洗練された答えであるかどうかはわかりませんが、そうでない場合は、エイリアスのインスタンスエラーが頻繁に発生すると予測しています。PS try id =(Key(PersistInt 64 n))

于 2012-02-02T20:13:33.090 に答える