haskell - 罗马人、 ruby 和 haskell

标签 haskell metaprogramming template-haskell

动机为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/

相关文章:

haskell - 为什么 Haskell/GHC 不支持记录名重载

Haskell:函数组合刚刚损坏了我的大脑

haskell - Haskell 中队列的使用(模块)

c++ - std::is_same 无法通过 constexpr 自动变量的 decltype 工作

metaprogramming - 了解 Raku 的 `&?BLOCK` 编译时变量

模板元编程的 Haskell 变体

haskell - 处理有限但任意数量的异构元素的函数

haskell - 如何实现十进制到二进制的转换

c++ - 如何将模板模板与模板实例进行比较?

haskell - 使用 makeClassy 制作具有相同字段名称的镜头 (TH)