函数可能会也可能不会实例化TypeClass的参数?

时间:2013-09-03 20:38:35

标签: haskell yesod

这就是我想让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,这样的事情是否可能?

2 个答案:

答案 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