4

我想建立一个抽象来使用不同的模板引擎:

class Template a where
  process :: a -> Model -> IO String

class TemplateEngine a where
  buildTemplate :: (Template b) => a -> BufferedReader -> IO b

我的第一次尝试是调整 Groovy 模板,因此我实现了所需的数据类型:

data GroovyWritable = mutable native groovy.lang.Writable where
  native writeTo :: GroovyWritable -> Writer -> IO Writer
      throws IOException

data GroovyTemplate = mutable native groovy.text.Template where
  native make :: GroovyTemplate -> HashMap -> IO GroovyWritable

data GroovyEngine = mutable native groovy.text.markup.MarkupTemplateEngine where
  native new            :: ()           -> IO GroovyEngine
  native createTemplate :: GroovyEngine -> BufferedReader -> IO GroovyTemplate
      throws ClassNotFoundException, IOException

然后我做了相应的实例:

instance Template GroovyTemplate where
   process template model = do -- model is not used at the moment
     config   <- HashMap.new ()
     writable <- GroovyTemplate.make template config
     stWriter <- StringWriter.new ()
     writer   <- writable.writeTo stWriter
     writer.toString

instance TemplateEngine GroovyEngine where
  buildTemplate engine reader = GroovyEngine.createTemplate engine reader

但是编译器抱怨:

...
type `GroovyTemplate` is not as polymorphic as suggested
    in the annotation where just `α` is announced.
...
type error in expression createTemplate engine reader
    type is : IO GroovyTemplate
    expected: IO α

有任何想法吗 ?我应该使用不同的策略吗?谢谢

更新

为了解释我正在尝试做什么,我添加了一个函数,该函数表示从给定模板引擎构建模板的通用方法。

假设我知道 Frege 需要更精确地了解模板文件的类型、实例TemplateEngineBufferedReader包含内容的内容,执行buildTemplate给定引擎的函数应该给我一个Template. 此处的此函数正在编译,根本没有任何警告。

execute :: (TemplateEngine a, Template b) => a -> BufferedReader -> IO b
execute engine reader = buildTemplate engine reader

我很困惑,为什么编译器不在这里抱怨?它不应该像以前一样抱怨吗?

更新二(工作解决方案)

按照 Ingo 的建议,我了解了我的设计背后的基本原理,并找到了一个可行的解决方案。

TemplateEngine一开始我认为让类型类以相同的方式创建模板引擎实例会很棒。

但最重要的部分是有一个通用的类型类来处理模板等,因为模板可以被缓存。所以底线是,只要生成的模板是Template.

在这个前提下,我可以有一个通用的函数来处理模板并获取生成的 html/json/xml...等。

execute :: (Template a) => a -> Model -> IO String
execute tpl model = tpl.process model

当然production-ready签名应该是这样的:

execute :: (Template a) => a -> Model -> Either TemplateException String
4

1 回答 1

1

我不完全确定您将要做什么,但就目前而言,该GroovyEngine.createTemplate方法不能用于将 teh 实例GroovyEngine化为TemplateEngine. 由于buildTemplate操作承诺返回Template调用者想要的任何内容,前提是Template实例作为参数传递。

现在,这里的第一个问题是本地方法无法处理类型类约束。Template我们可以通过使用实际使用约束的 frege 函数包装对本机方法的调用来解决这个问题。但是话又说回来,不清楚如何实际创建适当的值,因为Template该类不提供相应的操作。并且GroovyEngine.createTemplate仍然没有资格,因为它总是创建一个特定的模板,而不是一个依赖于约束的模板。

于 2016-01-19T16:57:37.697 回答