如何使用MultiPiece

时间:2012-02-02 14:10:12

标签: haskell yesod

我对Yesod完全不熟悉(并且在haskell方面不是很有经验)而且我正在尝试构建我的第一个处理程序。我使用默认参数(我使用Yesod 0.9.4.1版本并在scraffolding中选择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/sectors/1/1/1,2时,我得到的页面只包含:             内部服务器错误             Prelude.read:没有解析

好吧,我不完全明白这里的FooId是什么 - 如何从包含数字的字符串列表中创建这样的FooId列表?

当然,最需要一个如何使FooId成为MultiPiece实例的解决方案。


编辑:

Daniel和svachalek,感谢您的帖子 - 我尝试了您的(Daniel's)解决方案,但后来我收到错误,说[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

现在我在编译和运行时都没有出现任何错误,唯一不满意的是我总是收到Not Found的结果,即使我提供的参数可以给我一些结果 - 所以现在我有了找出如何确定哪些SQL确切地发送到数据库


编辑:

现在我看到“Not Found”与问题相关并且上面的编辑不是解决方案 - 当我浏览到localhost:3000 / foos / 4930000/3360000然后我得到了结果(但随后是FooIds是空的) - 但是当我添加类似:localhost:3000 / sectors / 4930000/3360000/1之类的东西时,我总是得到“Not Found” - 所以它仍然没有工作..

3 个答案:

答案 0 :(得分:1)

希望我能提供帮助,但据我所知,yesod与网络应用程序有关,因此我从未真正看过它。所以我可以尝试在空中刺,也许我会碰到一些东西。

Hayoo导致

class MultiPiece s where
    fromMultiPiece :: [Text] -> Maybe s
    toMultiPiece :: s -> [Text]
Yesod.Dispatch中的

。由于FooId似乎有Read个实例,可能还有Show个实例,您可以尝试

{-# 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

我不知道这是否接近正确的事情,我会把它作为评论发布,但它太长了,评论中没有太多的格式。如果它没有帮助,我会将其删除,以便在没有答案的情况下不再给出问题。

答案 1 :(得分:1)

问题解决了:))

您可以使用问题的最后一次修改中的我的实现,并浏览到以下网址:http://localhost:3000/foos/4930000/3360000/Key {unKey = PersistInt64 3}/Key {unKey = PersistInt64 4} Key类型派生Read但不是以非常友好(和预期)的方式:)

或者将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)

并使用以下网址:http://localhost:3000/foos/4930000/3360000/1/2

非常感谢Yesod Web Framework Google Group的David McBride


编辑:上述解决方案只有一个缺点 - 使用PersistInt64类型 - 使用这样的实现细节不是一个好习惯,但可以使用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也为此付出了代价!

答案 2 :(得分:0)

我也是Yesod的新手,我放弃并将-XTypeSynonymInstances添加到我的.cabal文件中的ghc-options中,到目前为止,它让我的生活变得更轻松。我不确定它是否是这个特定问题的最优雅答案,但我预测你会经常遇到该别名实例错误。附:尝试id =(Key(PersistInt 64 n))