如何使用多片

发布于 2025-01-01 08:29:21 字数 3999 浏览 2 评论 0原文

我对 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 的实例 - 如何解决此问题?


编辑: Daniel:嗯,实际上我不知道 FooId 到底是什么 - 它是 Yesod 魔法的一部分,到目前为止我还没有完全理解 - 它是从表定义中自动生成的 - 但它是某种数字。

因为我不知道如何使用 MultiPiece,所以我切换到更简单的解决方案并修改:

route: /foos/#Int/#Int/#String FoosReturnR GET

handler: [还添加了一些日志记录]

    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)解决方案,但随后我收到错误,指出需要 [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到数据库


编辑:

现在我看到“未找到”与问题相关,并且上述编辑不是解决方案 - 当我浏览到 localhost:3000/foos/4930000/3360000 时,我得到结果(但是 FooIds 是空的) - 但是当我添加类似以下内容时: localhost:3000/sectors/4930000/3360000/1 然后我总是得到“Not Found” - 所以它仍然不起作用..

I'm completely new to Yesod (and not very experienced in haskell) and I'm trying to build my first handler. I scraffolded my app using default parameters (I'm using Yesod 0.9.4.1 version and choose postgresql in scraffolding) and now I'm trying to retrieve some data from a table using selectList. I defined a new table (let's call it Foo) in models config file:

    Foo
        xStart Int
        yStart Int

and want to pass a list of FooId's and some other Foo attributes so I defined a route:

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

and a handler:

    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

I imported the handler in Application.hs and added it to cabal file and now when I'm trying to run it I receive an error saying that FooId is not an instance of MultiPiece - but when I try to make it an instance there is an error saying that FooId is a type synonym and cannot be an instance of MultiPiece - how to resolve this problem?


EDIT:
Daniel: well, actually I don't know what exactly is FooId - it's a part of Yesod's magic which I don't fully understand so far - it's generated automatically from the table definition - but it's a some kind of a number.

Because I don't know how to use MultiPiece I switched to simpler solution and modified:

route: /foos/#Int/#Int/#String FoosReturnR GET

handler: [added also some logging]

    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

and now it is compiling but when I browse to: http://localhost:3000/sectors/1/1/1,2 I get a page containing only:
Internal Server Error
Prelude.read: no parse

Well, I don't fully understand what is FooId here - how to create such a list of FooId's from list of strings containing numbers?

And of course a solution of how to make the FooId an instance of MultiPiece is most wanted.


EDIT:

Daniel and svachalek, thanks for your posts - I tried your (Daniel's) solution but then I was receiving errors saying that [FooId] is expected (as in the handler function declaration) but FooId type was given and this lead me to the following solution:

    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

of course I changed the route to: /foos/#Int/#Int/*FooIds FoosReturnR GET

and the handler to:

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

and now I don't get any errors during compilation nor runtime, and the only not satisfying thing is that I always receive Not Found as a result, even if I supply parameters that should give me some results - so now I have to figure out how to determine what SQL was exactly sent to the database


EDIT:

Now I see that the "Not Found" is connected to the problem and that the above edit is not a solution - when I browse to localhost:3000/foos/4930000/3360000 then I get the results (but then the FooIds is empty) - but when I add something like: localhost:3000/sectors/4930000/3360000/1 then I always get "Not Found" - so it's still not working..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一生独一 2025-01-08 08:29:21

希望我能提供帮助,但据我所知,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

我不知道这是否接近正确的事情,我本来想把它作为评论发布的,但它太长了,而且评论中没有太多格式。如果它没有帮助,我将删除它,以免给人留下你的问题已经有答案的印象,而实际上它还没有答案。

Wish I could help, but yesod has something to do with web applications, as far as I know, hence I've never really looked at it. So I can just try a stab in the air, maybe I hit something.

Hayoo leads to

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

in Yesod.Dispatch. Since FooId seems to have a Read instance and probably a Show instance, you could try

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

I have no idea whether that is close to the right thing, and I would have posted it as a comment, but it's too long and there's not much formatting in comments. If it doesn't help I will delete it to not give the impression your question already has an answer when it hasn't.

拥抱影子 2025-01-08 08:29:21

问题已解决:)

您可以使用问题的最后编辑之一中的我的实现,然后浏览到如下 URL: 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)

并使用类似以下的 URL: http://localhost:3000/foos/4930000/3360000/1/ 2

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


编辑:上述解决方案只有一个缺点 - 使用 PersistInt64 类型 - 它不是一个使用这样的实现细节是一种很好的做法,但可以通过使用 Database.Persist 中的 fromPersistValuetoPersistValue 函数来修复它,如下所示

    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))

: ,也非常感谢大卫·麦克布莱德!

The problem is solved:)

You could either use my implementation from one of the last edits of the question and browse to URL like: http://localhost:3000/foos/4930000/3360000/Key {unKey = PersistInt64 3}/Key {unKey = PersistInt64 4}
The Key type derives Read but not in a very friendly (and expected) way:)

Or change the implementation of fromMultiPiece to:

    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)

and use URLs like: http://localhost:3000/foos/4930000/3360000/1/2

Many thanks to David McBride from the Yesod Web Framework Google Group


EDIT: the above solution had only one disadvantage - using the PersistInt64 type - it's not a good practice to use such a details of implementation, but it can be repaired by using fromPersistValue and toPersistValue functions from Database.Persist as follows:

    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))

Again, big thanks to David McBride also for this!

土豪我们做朋友吧 2025-01-08 08:29:21

我对 Yesod 也相当陌生,我屈服了并将 -XTypeSynonymInstances 添加到我的 .cabal 文件中的 ghc-options 中,到目前为止,它让我的生活变得更加轻松。我不确定这是否是对这个特定问题的最优雅的答案,但否则我预测您会经常遇到别名实例错误。 PS 尝试 id = (Key (PersistInt 64 n))

I'm also fairly new to Yesod and I gave in and added -XTypeSynonymInstances to the ghc-options in my .cabal file, and so far it's made life a lot easier for me. I'm not sure if it's the most elegant answer to this particular problem, but otherwise I predict you'll run into that instance-of-alias error pretty frequently. P.S. try id = (Key (PersistInt 64 n))

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文