1

这就是我试图让我的处理程序看起来像 -

getUserStudentsR :: UserId -> Handler TypedContent
getUserStudentsR userId = 
      getStudentEntitiesForCoach userId 
      >>= returnTypedContent . map toUserStudentResponse 

其中学生是一个持久实体(细节大多不重要)和

getStudentEntitiesForCoach :: UserId -> HandlerT App IO [Entity Student]
getStudentEntitiesForCoach coachId = 
    runDB $ selectList [StudentPrimaryCoachId ==. Just(coachId)] [] 

data UserStudentResponse = StudentResponse (Key Student) Student

instance ToJSON UserStudentResponse where
    toJSON (StudentResponse studentId student) = 
          object
                  [
                      "login" .= studentLogin student
                      , "studentId" .= studentId
                      , "firstName" .= studentFirstname student
                      , "lastName" .= studentLastname student

                  ]

toUserStudentResponse :: (Entity Student) -> UserStudentResponse
toUserStudentResponse (Entity studentId student) 
    = StudentResponse studentId student

returnTypedContent x = selectRep $ do 
                          provideJson x

现在很明显,除非 UserStudentResponse 实例化 ToJSON 并提供 toJSON 的实现,否则这不会编译。但是,我想让 returnTypedContent 函数通用 - 比如 -

returnTypedContent x = selectRep $ do 
                         -- if ToJSON x -- 
                            provideJSON x
                         -- if ToHTML x -- -- note this is not an either or
                            provideRep $ return $ toHtml $ a

我想这样做,以便可以扩展 returnTypedContent 以提供各种内容类型的返回,然后根据处理程序中使用的数据类型是否实例化某些类型类(例如 ToJSON),我们提供了不同的东西。

如果不进入 Template Haskell,这样的事情可能吗?

4

2 回答 2

1

你可以使用这样的东西(启用 GADT):

data Wrapper a where
    Json :: ToJSON a => a -> Wrapper a
    Html :: ToHTML a => a -> Wrapper a

然后你可以模式匹配:

returnTypedContent (Json x) = selectRep (provideJSON x)
returnTypedContent (Html x) = selectRep (provideRep $ return $ toHtml x)

您必须明确地包装您的数据,但这应该不会太成问题。

于 2013-09-04T10:32:02.497 回答
0

You can't do this. GHC currently provides no way to "match on the instance head"

So it is impossible to have

instance Foo a => Bar a where ...
instance Bar a where ...

where the dispatch chooses between them if Foo matches.

But you can, with closed type families, give fallthroughs in specific instances. The GHC manual demonstrates this technique: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/type-families.html#closed-type-families

于 2015-03-26T15:49:42.667 回答