1

これは、ハンドラーを次のように見せようとしているものです-

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

ここで、Student は永続エンティティ (詳細はほとんど重要ではありません) であり、

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 に答える