href 属性的 PostsController

PostsController for href attribute

以下:

instance View EditView where
    html EditView { .. } = [hsx|
        <nav>
            <ol class="breadcrumb">
                <li class="breadcrumb-item"><a href={PostsAction}>Posts</a></li>
                <li class="breadcrumb-item active">Edit Post</li>
            </ol>
        </nav>
        <h1>Edit Post</h1>
        {renderForm post}
    |]

来自 IHP 指南 Creating Your First Project 部分中博客项目的代码。

我主要将它从 HSX 转换为 blaze-html:

instance View EditView where
    html EditView { .. } = do
        H.nav $ do
            H.ol ! A.class_ "breadcrumb" $ do
                H.li ! A.class_ "breadcrumb-item" $ do
                    H.a ! A.href "PostsAction" $ do
                        "Posts"
                H.li ! A.class_ "breadcrumb-item active" $ do
                    "Edit Post"
        H.h1 "Edit Post"
        renderForm post

我想知道的最后一点是这个:

<a href={PostsAction}>Posts</a>

如果我执行以下操作:

H.a ! A.href PostsAction $ do
    "Posts"

我收到这条消息:

• Couldn't match expected type ‘H.AttributeValue’
              with actual type ‘PostsController’
• In the first argument of ‘A.href’, namely ‘PostsAction’
  In the second argument of ‘(!)’, namely ‘A.href PostsAction’
  In the expression: H.a ! A.href PostsActiontypecheck
PostsAction
Defined at /home/dharmatech/Dropbox/Documents/ihp-blog/blog/Web/Types.hs:13:7

PostsAction 传递给 A.href 的好方法是什么?

(如果还有其他方法可以使blaze-html表达式更地道,也欢迎推荐。:-))

更新 1

当我使用以下内容时,按照 Willem 在他下面的回答中建议的内容:

instance View EditView where
    html EditView { .. } = do
        H.nav $ do
            H.ol ! A.class_ "breadcrumb" $ do
                H.li ! A.class_ "breadcrumb-item" $ do
                    H.a ! A.href (fromString (show PostsAction)) $ do
                        "Posts"
                H.li ! A.class_ "breadcrumb-item active" $ do
                    "Edit Post"
        H.h1 "Edit Post"
        renderForm post

我得到以下信息:

• Couldn't match type ‘Text’ with ‘[Char]’
  Expected type: String
    Actual type: Text
• In the first argument of ‘fromString’, namely
    ‘(show PostsAction)’
  In the first argument of ‘A.href’, namely
    ‘(fromString (show PostsAction))’
  In the second argument of ‘(!)’, namely
    ‘A.href (fromString (show PostsAction))’typecheck

也许我需要导入 fromStringText 版本?

更新 2

我添加了以下导入:

import Data.String(IsString(fromString))

但是,错误信息是一样的:

• Couldn't match type ‘Text’ with ‘[Char]’
  Expected type: String
    Actual type: Text
• In the first argument of ‘fromString’, namely
    ‘(show PostsAction)’
  In the first argument of ‘A.href’, namely
    ‘(fromString (show PostsAction))’
  In the second argument of ‘(!)’, namely
    ‘A.href (fromString (show PostsAction))’typecheck

更新 3

如果我将鼠标悬停在 show 上,将显示以下签名:

show :: forall a. Show a => a -> Text

对于fromString

fromString :: forall a. IsString a => String -> a

所以我认为这就是不匹配的地方。

更新 4

这是一个典型的 IHP 视图文件,我在导入的顶部有以下内容:

module Web.View.Posts.Edit where
import Web.View.Prelude

import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A

正如 documentation on Inline Haskell 所说:

If the variable is another HSX expression, a blaze HTML element, a text or string: it is just included as you would expect.

If the variable is any other custom Haskell data structure: it will first be converted to a string representation by calling show on it. You can add a custom ToHtml (import it from IHP.HSX.ToHtml) instance, to customize rendering a data structure.

所以除非 [hsx|…] 准引号中有 ToHTML {PostAction},否则你应该应用 show,接下来我们调用 fromString :: IsString a => String -> a将其转换为 AttributeValue.

代码因此等同于:

instance View EditView where
    html EditView { .. } = do
        H.nav $ do
            H.ol ! A.class_ "breadcrumb" $ do
                H.li ! A.class_ "breadcrumb-item" $ do
                    H.a ! A.href (<strong>fromString (show PostsAction)</strong>) $ do
                        "Posts"
                H.li ! A.class_ "breadcrumb-item active" $ do
                    "Edit Post"
        H.h1 "Edit Post"
        renderForm post