动机为Romans, rubies and the D ,我想看看在 Haskell 中是否可以做同样的事情。
module Romans where
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import Data.Text
num :: String -> String
num s = rep $ pack s
where
r1 s1 = replace (pack "IV") (pack "IIII") s1
r2 s2 = replace (pack "IX") (pack "VIIII") s2
r3 s3 = replace (pack "XL") (pack "XXXX") s3
r4 s4 = replace (pack "XC") (pack "LXXXX") s4
rep = unpack . r4 . r3 . r2 . r1
value :: String -> Int
value s = cnt $ pack s
where
c1 s1 = (count (pack "I") s1) * 1
c2 s2 = (count (pack "V") s2) * 5
c3 s3 = (count (pack "X") s3) * 10
c4 s4 = (count (pack "L") s4) * 50
c5 s5 = (count (pack "C") s5) * 100
cnt t = c5 t + c4 t + c3 t + c2 t + c1 t
roman :: String -> ExpQ
roman s = return $ LitE (IntegerL (compute s))
where
compute s = fromIntegral $ value $ num s
和:
{-# LANGUAGE TemplateHaskell #-}
import Romans
main = print $ $(roman "CCLXXXI")
首先,由于我是 Template Haskell 的新手,我想知道我是否做对了。实际计算发生在编译时,对吗?
第二,如何改进语法?
而不是 $(roman "CCLXXXI")
我想要类似 roman "CCLXXXI"
的东西,甚至更好的东西。到目前为止我还未能改进语法。
最佳答案
The actual computation happens at compile time, correct?
正确。您的 Template Haskell 代码正在生成一个整数文字,显然必须在编译时对其进行评估。要在运行时进行计算,您必须生成其他类型的表达式,例如函数应用程序。
and second, how do I improve the syntax?
你不能,真的。编译时代码的设计目的是从常规代码中脱颖而出,这是有充分理由的,因为编译时代码的行为可能与常规代码完全不同。另一种方法是编写一个准引号,它允许您使用语法 [roman|相反,CCLXXXI |]
。
但是,这里使用 ($)
运算符是多余的,因此您也可以编写
print $(roman "CCLXXI")
这可能看起来更漂亮一点。
关于haskell - 罗马人、 ruby 和 haskell ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9949069/