2

提前为我的 Haskell 缺乏经验道歉。我正在为一个学习项目的 Redis 实例编写一个小包装器。到目前为止,Yesod 绝对是一个奇迹。凭借很少的 Haskell 经验,我得到了 browserId Auth 工作,并且我成功快速地将记录插入 Redis。

我一直在弄清楚如何将 Redis 响应转换为 JSON 并发回。这是一个工作的、非脚手架的应用程序,它显示了获取静态 RepJson 或带有 Redis 信息的 RepPlain(应用程序称为 LRedis):

{-# LANGUAGE OverloadedStrings, TemplateHaskell, TypeFamilies,
             MultiParamTypeClasses, QuasiQuotes #-}

import Yesod
import Data.Text
import Data.Text.Encoding
import Data.ByteString.UTF8
import Database.Redis
import qualified Data.ByteString.Lazy as L


data LRedis = LRedis

instance Yesod LRedis where

mkYesod "LRedis" [parseRoutes|
    / HomeR GET
    /learnJson LearnJsonR GET
    /redisWorks RedisWorksR GET
    |]

getHomeR :: Handler RepHtml
getHomeR = do
    defaultLayout[whamlet|
    <p>Hi this is a headless API thing.
    |]

getLearnJsonR :: Handler RepJson
getLearnJsonR = do
    jsonToRepJson $ object [("json", ("ftw"::Text))]

getRedisWorksR :: Handler RepPlain
getRedisWorksR = do
    conn <- liftIO $ connect defaultConnectInfo
    liftIO $ runRedis conn $ do
        result <- Database.Redis.get (fromString "hello")
        case result of
            Left e -> return $ RepPlain "Error"
            Right mAnswer -> do
                case mAnswer of
                    Nothing -> return $ RepPlain "Not found."
                    Just x -> return $ RepPlain (toContent x)

main :: IO()
main = do
    warpDebug 3000 $ LRedis

同样,一切正常。如果您 curl ,它将返回存储在 redis 中“hello”中的字符串,如果您 curl /redisWorks,它将返回 JSON /learnJson,但我想将 redis 答案作为 JSON 给出,而不是纯字符串。我以为我可以天真地将两者结合起来,例如:

getRedisJsonR :: Handler RepJson
getRedisJsonR = do
    conn <- liftIO $ connect defaultConnectInfo
    liftIO $ runRedis conn $ do
        result <- Database.Redis.get (fromString "hello")
        case result of
            Left e -> jsonToRepJson $ object [("response", ("error"::Text))]
            Right mAnswer -> do
                case mAnswer of
                    Nothing -> jsonToRepJson $ object [("response", ("Nothing"::Text))]
                    Just x -> jsonToRepJson $ object [("response", ((decodeUtf8 x)::Text))]

但是在添加路由后,/redisJson RedisJsonR GET它会因为这个编译错误而失败:

Couldn't match expected type `Redis a0'
            with actual type `GHandler sub0 master0 RepJson'
In the expression:
  jsonToRepJson $ object [("response", ("error" :: Text))]
In a case alternative:
    Left e -> jsonToRepJson $ object [("response", ("error" :: Text))]
In a stmt of a 'do' block:
  case result of {
    Left e -> jsonToRepJson $ object [("response", ("error" :: Text))]
    Right mAnswer
      -> do { case mAnswer of {
                Nothing -> ...
                Just x -> ... } } }

似乎它告诉我我需要result在出现错误的情况下做一些不同的事情,但我不知道那会是什么,或者考虑到 RepPlain 版本正在运行,为什么它是必要的。

有没有在 Yesod 中将 Redis 的结果转换为 JSON 的示例?
是否有一些简单的事情我在 IO 上做错了什么?

Hedis 文档的便捷链接:http://hackage.haskell.org/package/hedis感谢 您帮助我。如果事实证明它非常简单,再次抱歉。

4

1 回答 1

1
getRedisJsonR :: Handler RepJson
getRedisJsonR = do
    conn <- liftIO $ connect defaultConnectInfo
    res <- liftIO $ runRedis conn $ do
        result <- Database.Redis.get (fromString "hello")
        case result of
            Left e -> return $ jsonToRepJson $ object [("response", ("error"::Text))]
            Right mAnswer -> do
                case mAnswer of
                    Nothing -> return $ jsonToRepJson $ object [("response", ("Nothing"::Text))]
                    Just x -> return $ jsonToRepJson $ object [("response", ((decodeUtf8 x)::Text))]
    res

实际上,我不相信自己能解释为什么这行得通,而您的原始代码却行不通——我每天都在 Haskell 中编程不到三个月,所以我对什么会起作用有一种正在发展的直觉,但是我真的还没有在理论方面,特别是当涉及到堆叠的 monad 时,我认为这是我们在这里处理的(Redis 位于 Handler 之上,反之亦然,liftIO 正在促进堆叠) .

希望其他人可以参与进来——这似乎是一个很好的具体例子来说明一些 monad 概念。

于 2013-04-17T14:57:22.720 回答