You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 01:25:06