处理许多不相关的类型时避免使用样板 [英] Avoiding boilerplate when dealing with many unrelated types

查看:113
本文介绍了处理许多不相关的类型时避免使用样板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写处理来自 Language.Exts.Annotated.Syntax ,其中定义了各种类型的镜像Haskell模块的结构:

  data模块l = ... 
数据Decl l = ...
数据Exp t = ...
- etc

我希望能够编写遍历这些数据结构并执行各种操作的函数对他们进行改造。因为没有一种常见的数据类型,所以我不能编写一个完成所有工作的函数。



到目前为止,我已经写了 Tree 类型,它们包装每一种类型,以便我的转换函数可以执行 Tree l - >树l

 数据树l = ModuleT(模块l)
| DeclT(Decl l)
| ExpT(Exp l)
- etc copy&粘贴

但是现在我发现自己编写了很多需要 Module ,将它封装 ModuleT ,调用一个函数,然后将结果解开为 Module 再次。我有:

  class AnnotatedTree ast其中
tree :: ast l - >树l
untree ::树l - > ast l

实例AnnotatedTree模块其中
tree = ModuleT
untree(ModuleT x)= x
untree _ =错误expected ModuleT

- etc ad nauseam

两个问题:


  1. 鉴于我无法更改Language.Exts.Annotated.Syntax中的类型,我是否会以错误的方式进行操作?

  2. 如果不是,我可以减少所有这些样板吗?
  3. 所有这些类型似乎成为Typeable和Data的实例。您可以将您的类型树定义为Typeable和Data的实例,然后使用其中一个可用的泛型库(SYB,uniplate,...)轻松遍历Tree。



    我个人最喜欢的是uniplate。例如,从树中收集所有的GuardedAlt会很简单:

      import Data.Uniplate.PlateData 

    ...

    allGuardedAlts :: Tree l - > [l]
    allGuardedAlts t = [l | GuardedAlt l _ _< - universeBi t]

    你可以看看我的包 graphtype 我做了类似的事情。


    I'm writing code that deals with values from Language.Exts.Annotated.Syntax, where a variety of types are defined that mirror the structure of a Haskell module:

    data Module l = ...
    data Decl l = ...
    data Exp t = ...
    -- etc
    

    I'd like to be able to write functions that walk these data structures and perform various transformations on them. Because there's no one common data type, I can't write one function that does everything.

    So far I've written a Tree type that wraps each of these types so that my transformation function can do Tree l -> Tree l:

    data Tree l = ModuleT (Module l)
                | DeclT (Decl l)
                | ExpT (Exp l)
                -- etc copy & paste
    

    However I'm now finding myself writing a lot of code that takes a Module, wraps it ModuleT, calls a function, then unwraps the result back to Module again. I have:

    class AnnotatedTree ast where
      tree :: ast l -> Tree l
      untree :: Tree l -> ast l
    
    instance AnnotatedTree Module where
      tree = ModuleT
      untree (ModuleT x) = x
      untree _ = error "expected ModuleT"
    
    -- etc ad nauseam
    

    Two questions:

    1. Given that I can't change the types in Language.Exts.Annotated.Syntax, am I going about this the wrong way?
    2. If not, can I cut down on all this boilerplate somehow?

    解决方案

    All of those types seem to be instances of Typeable and Data. You can define your type Tree to be an instance of Typeable and Data as well, and then use one of the available generics libraries (SYB, uniplate, ...) to traverse the Tree with ease.

    My personal favorite is uniplate. For example, collecting all GuardedAlt from Tree would be as easy as:

    import Data.Uniplate.PlateData
    
    ...
    
    allGuardedAlts :: Tree l -> [l]
    allGuardedAlts t = [ l | GuardedAlt l _ _ <- universeBi t]
    

    You could take a look at my package graphtype where I did similar things.

    这篇关于处理许多不相关的类型时避免使用样板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆