Haskell 可能实例化或不实例化TypeClass的函数参数?

Haskell 可能实例化或不实例化TypeClass的函数参数?,haskell,yesod,Haskell,Yesod,这就是我想让我的处理者看起来的样子- getUserStudentsR :: UserId -> Handler TypedContent getUserStudentsR userId = getStudentEntitiesForCoach userId >>= returnTypedContent . map toUserStudentResponse 其中,Student是一个持久的实体(细节大多不重要),并且 及 现在很明显,除非Use

这就是我想让我的处理者看起来的样子-

getUserStudentsR :: UserId -> Handler TypedContent
getUserStudentsR userId = 
      getStudentEntitiesForCoach userId 
      >>= returnTypedContent . map toUserStudentResponse 
其中,Student是一个持久的实体(细节大多不重要),并且

现在很明显,除非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以提供各种ContentType的返回,然后根据处理程序中使用的数据类型是否实例化某些类型的类(例如ToJSON),我们提供了不同的内容


在不进入模板Haskell的情况下,这样做可能吗?

您可以使用这样的方法(启用GADTs):

然后您可以进行模式匹配:

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

您必须显式地包装数据,但这不会有太大问题。

您可以使用类似的方法(启用GADT):

然后您可以进行模式匹配:

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

您必须显式地包装数据,但这不会有太大问题。

您不能这样做。GHC目前没有提供“在实例头上匹配”的方法

所以这是不可能的

instance Foo a => Bar a where ...
instance Bar a where ...
如果Foo匹配,调度将在两者之间进行选择


但是,对于闭合类型族,可以在特定实例中给出错误提示。GHC手册演示了这项技术:

您不能这样做。GHC目前没有提供“在实例头上匹配”的方法

所以这是不可能的

instance Foo a => Bar a where ...
instance Bar a where ...
如果Foo匹配,调度将在两者之间进行选择


但是,对于闭合类型族,可以在特定实例中给出错误提示。GHC手册演示了这项技术:

我不是一个真正的YesSOD用户,但是
selectRep
做什么?仅仅为
UserStudentResponse
创建一个
ToTypedContent
实例就足够了吗?你不能直接这样做(以其他人想出一些聪明的把戏的机会为代价);像
ToJSON[a]
这样的约束是命题,而不是语言内部的布尔值。尝试写下
returnTypedContent
的类型。这将有助于了解您为什么不能这样做,并可能有助于设计一个变通方法(尽管我现在不知道它是什么样子)。使用
-XOverlappingInstances
,您可以创建
ToJSON
ToHTML
的“回退”实例。您可能能够专门处理从回退实例中获得的值(如果没有通常禁止使用的json/html值,它们可能是
抛出一些异常值
)。我认为最好使用模板haskell编写大量实例。@aavogt-我将尝试回退实例。现在需要阅读它们。同意,template haskell可能是实现这一目标的唯一方法,但如果可以,我想避免它。我不是一个真正的YesSOD用户,但是
selectRep
做什么呢?仅仅为
UserStudentResponse
创建一个
ToTypedContent
实例就足够了吗?你不能直接这样做(以其他人想出一些聪明的把戏的机会为代价);像
ToJSON[a]
这样的约束是命题,而不是语言内部的布尔值。尝试写下
returnTypedContent
的类型。这将有助于了解您为什么不能这样做,并可能有助于设计一个变通方法(尽管我现在不知道它是什么样子)。使用
-XOverlappingInstances
,您可以创建
ToJSON
ToHTML
的“回退”实例。您可能能够专门处理从回退实例中获得的值(如果没有通常禁止使用的json/html值,它们可能是
抛出一些异常值
)。我认为最好使用模板haskell编写大量实例。@aavogt-我将尝试回退实例。现在需要阅读它们。同意,模板haskell可能是实现这一目标的唯一方法,但如果可以,我想避免它。不。。这不是一个“如果”的问题。。如果一个实例同时实例化了ToJSON和ToHTML,我的代码需要同时执行(provideJSON和provideRep),也就是说,YesSOD可以选择响应这两种类型的内容类型请求。。按照您的方式,如果有一个实例化ToJSON的实例,它将永远不会执行provideRep。也。。我无法发送不实现ToJSON或ToHTML的“a”。顺便说一句,@RoopeshShenoy:您当然可以扩展包装器,使其同时包含
构造函数。(您最好使用@aavogt的
OverlappingInstances
建议。但是我会为selectRep创建一个单独的类型类,并在那里使用重叠,而不是
ToJSON
ToHTML
)有趣的建议,让我看看是否有类似的事情works@RoopeshShenoy:我一直在玩弄
重叠实例
有一段时间了,我不确定我的建议是否有效。不。。这不是一个“如果”的问题。。如果一个实例同时实例化了ToJSON和ToHTML,我的代码需要同时执行(provideJSON和provideRep),也就是说,YesSOD可以选择响应这两种类型的内容类型请求。。按照您的方式,如果有一个实例化ToJSON的实例,它将永远不会执行provideRep。也。。我无法发送不实现ToJSON或ToHTML的“a”。顺便说一句,@RoopeshShenoy:您当然可以扩展包装器,使其同时包含
构造函数。(您最好使用@aavogt的
OverlappingInstances
建议。但是我会为selectRep创建一个单独的类型类,并在那里使用重叠而不是
ToJSON
ToHTML
)有趣的建议,让我看看是否有类似的东西works@RoopeshSheno
instance Foo a => Bar a where ...
instance Bar a where ...