frege – Type不像建议的那样具有多态性

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

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

当然,生产就绪签名应该是这样的:

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

最佳答案 我不完全确定你将要做什么,但就目前而言,GroovyEngine.createTemplate方法不能用于将GroovyEngine实例化为TemplateEngine.由于buildTemplate操作承诺返回调用者想要的任何模板,前提是模板实例作为参数传递.

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

点赞