IHP邮件模板调用返回HTML函数出现编译报错问题
IHP邮件模板中调用HTML片段函数触发类型不匹配错误
问题详情
使用IHP Pro 1.0.0通过IDE生成标准邮件模板时,为动态构建HTML表格编写了接收列表并返回HTML的函数。但在BuildMail实例的[hsx|...|]块中调用该函数时,触发编译错误:
Couldn't match type ‘context’ with ‘ControllerContext’ arising from a functional dependency between constraints: ‘?context::ControllerContext’ arising from a use of ‘renderList’ at Admin/Mail/Accounts/Report.hs:(16,35)-(47,6) ‘?context::context’ arising from the type signature for: IHP.MailPrelude.html :: forall context. (?context::context, ConfigProvider context) => ...
- 该返回HTML的函数本身可正常编译
- 即便函数无参数,只要返回
Html类型就会报错;返回String或Text则正常 - 相同函数在非邮件视图中可正常使用
示例代码:
module Admin.Mail.Static.Test where import Admin.View.Prelude import IHP.MailPrelude data TestMail = TestMail { user :: User } instance BuildMail TestMail where subject = "Subject" to TestMail { .. } = Address { addressName = Just "Firstname Lastname", addressEmail = "fname.lname@example.com" } from = "hi@example.com" html TestMail { .. } = [hsx| Hello World {renderFoo} |] renderFoo :: Html renderFoo = [hsx|foo|]
原因分析
IHP中,普通视图的上下文是ControllerContext,而邮件模板的html方法要求的是任意满足ConfigProvider约束的上下文。你编写的renderFoo函数通过hsx生成Html时,隐式依赖了当前上下文为ControllerContext(这是普通视图的默认上下文),但邮件模板的上下文并不匹配这个类型,因此触发类型不匹配错误。
解决方案
修改HTML片段函数的类型签名,使其兼容任意满足ConfigProvider约束的上下文,而非固定依赖ControllerContext。
修改后的示例代码
module Admin.Mail.Static.Test where import Admin.View.Prelude import IHP.MailPrelude data TestMail = TestMail { user :: User } instance BuildMail TestMail where subject = "Subject" to TestMail { .. } = Address { addressName = Just "Firstname Lastname", addressEmail = "fname.lname@example.com" } from = "hi@example.com" html TestMail { .. } = [hsx| Hello World {renderFoo} |] -- 修改类型签名,兼容任意满足ConfigProvider的上下文 renderFoo :: (?context::context, ConfigProvider context) => Html renderFoo = [hsx|foo|]
扩展说明
如果你的函数需要处理列表(比如动态构建表格),同样需要确保列表渲染函数(如renderList)也使用通用上下文约束,而非绑定到ControllerContext。例如:
renderUserList :: (?context::context, ConfigProvider context) => [User] -> Html renderUserList users = [hsx| <table> {forEach users renderUserRow} </table> |] renderUserRow :: (?context::context, ConfigProvider context) => User -> Html renderUserRow user = [hsx| <tr> <td>{user.name}</td> <td>{user.email}</td> </tr> |]
内容的提问来源于stack exchange,提问作者stephenbenedict
相关产品推荐
相关产品推荐

