哈姆雷特模板中的紧凑型 if-then-else

Compact if-then-else in Hamlet templates

我试图理解 Yesod 的 Hamlet 中的变量插值,特别是实现类似 if-then-else 的逻辑。假设我想根据整数 x 的值添加 CSS 样式。 x 来自模板中的 for 循环,即我无法从 Haskell 代码访问它。

想要的结果:

<span class="even positive">2</span>
<span class="odd positive">13</span>
<span class="odd non-positive">-1</span>
<span class="even non-positive">0</span>

尝试内联 if:

<span class="#{if even x then "even" else "odd"} ...">#{x}</span>

尝试使用 $with:

$with cls <- (if even x then "even" else "odd")
    <span class="#{cls}">#{x}</span>

都不行;两者都导致

• Illegal variable name: ‘if’
  When splicing a TH expression

显然 Haskell 语法的那一部分没有在 #{...} 解析器中实现。有没有一种干净的方法可以做到这一点?我目前只能看到一条出路,而且非常丑陋:

$if ((even x) && (x > 0))
    <span class="even positive">#{x}</span>
$elseif (even x)
    <span class="even non-positive">#{x}</span>
$elseif (x > 0)
    <span class="odd positive">#{x}</span>
$else
    <span class="odd non-positive">#{x}</span>

大多数 Haskell 语法在这些模板表达式中不受支持。我认为这是设计使然,因为您不希望您的模板包含复杂的业务逻辑。

我会在 Haskell 端将代码编写为一个函数,然后从模板中调用它。类似于:

-- .hs file
altclass, signclass :: Int -> String
altclass x = if even x then "even" else "odd"
signclass x = if x > 0 then "positive" else "non-positive"

-- .hamlet file
<span class="#{altclass x} #{signclass x}">#{x}</span>

这样做可以正确地将业务逻辑从模板中分离出来,但仍然允许您使用模板内变量。