我想建立一个抽象来使用不同的模板引擎:
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 需要更精确地了解模板文件的类型、实例TemplateEngine
和BufferedReader
包含内容的内容,执行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