在两级树类型中使用Uniplate

Dan*_*ter 5 haskell parsec

我正处于在Haskell中为类C语言编写解析器的开始阶段.我已经得到了AST数据类型,并且在我深入研究解析器方面之前,我正在通过在AST本身上编写一些简单的查询来解决它.

我的AST围绕两种类型:语句(没有值,如if/ else)和表达式(有一个值,如文字或二进制操作).所以它看起来像这样(当然非常简化):

data Statement
    = Return Expession
    | If Expression Expression

data Expression
    = Literal Int
    | Variable String
    | Binary Expression Op Expression
Run Code Online (Sandbox Code Playgroud)

假设我想获取表达式中使用的所有变量的名称.使用uniplate,很容易:

varsInExpression exp = concat [s | Variable s <- universe exp]
Run Code Online (Sandbox Code Playgroud)

但是,如果我想在语句中找到变量列表呢?在每个构造函数中Statement,都有一个Expression我应该应用的嵌套varsInExpression.所以目前,看起来我必须对每个Statement构造函数进行模式匹配,这是uniplate要避免的.我只是没有充分了解文档,或者这是uniplate的限制(或者我做错了吗?)?

Dan*_*zer 8

对于双板来说,这似乎是一个很好的用例.我依赖于较慢的Data.Data方法,但这使得这段代码非常简单.

{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Typeable
import Data.Generics.Uniplate.Data
data Statement
    = Return Expression
    | If Expression Expression
    deriving(Data, Typeable)

data Expression
    = Literal Int
    | Variable String
    | Binary Expression Int Expression
    deriving(Data, Typeable)

vars :: Statement -> [String]
vars stmt = [ s | Variable s <- universeBi stmt]
Run Code Online (Sandbox Code Playgroud)

基本上,双元素是单一的概念,其中目标类型不一定与源相同,例如

biplate :: from -> (Str to, Str to -> from)
Run Code Online (Sandbox Code Playgroud)