这就是我想让Handler看起来像 -
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以提供各种contenttypes的返回,然后根据处理程序中使用的数据类型是否实例化某些类型类(例如ToJSON),我们提供了不同的东西。
如果没有进入模板Haskell,这样的事情是否可能?
答案 0 :(得分: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)
您必须明确地包装您的数据,但这不应该太成问题。
答案 1 :(得分:0)
你不能这样做。 GHC目前无法“匹配实例头”
所以不可能有
instance Foo a => Bar a where ...
instance Bar a where ...
如果Foo匹配,调度将在它们之间进行选择。
但是可以,在封闭类型系列中,在特定实例中给出了漏洞。 GHC手册演示了这种技术:https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/type-families.html#closed-type-families