类型不像建议

时间:2016-01-19 07:04:48

标签: frege

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

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

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

更新II(工作解决方案)

按照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

1 个答案:

答案 0 :(得分:1)

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

现在,第一个问题是本机方法无法处理类型类约束。我们可以通过使用实际使用Template约束的frege函数包装对本机方法的调用来解决此问题。但话说再说一遍,目前还不清楚如何实际创建一个合适的值,因为Template类并没有提供相应的操作。并且GroovyEngine.createTemplate仍然符合条件,因为它始终会创建一个特定的模板,而不是依赖于约束的模板。