我对 Haskell(我目前正在尝试学习的语言)中的递归数据结构有疑问。
我想用类似 Haskell Prolog 的术语进行编码,但我想出的每个解决方案都有不同的缺点,我真的想避免这些缺点。如果您希望从这个角度看待我的问题,我想找到一种廉价而优雅的方式来在 Haskell 类型中编码 BNF 语法。
提醒一下,一些序言术语可能是male
, sum(2, 3.1, 5.1)
, btree(btree(0, 1), Variable)
.
解决方案 1
data Term = SConst String
| IConst Integer
| FConst Double
| Var String
| Predicate {predName :: String, predArgs :: [Term]}
使用此解决方案,我可以嵌套谓词(因为predArgs
are Term
),但我无法将谓词与类型签名中的其他术语区分开来。
解决方案 2
data Term = SConst String
| IConst Integer
| FConst Double
| Var String
data Predicate = Predicate {predName :: String, predArgs ::[Either Term Predicate}
在这个变体中,我可以清楚地将谓词与基本术语区分开来,但是列表中的Either
类型在predArgs
代码的后面管理起来可能会很麻烦(我认为......我是 Haskell 的新手)。
解决方案 3
data Term = SConst String
| IConst Integer
| FConst Double
| Var String
| Struct String [Term]
data Predicate = Predicate String [Term]
使用最后一个解决方案,我像以前一样将术语拆分为两种不同的类型,但这次我避免Either Term Predicate
添加一个Struct
与.Term
Predicate
就像解决方案 1 有两个谓词构造函数。一种是启用递归的,Struct
另一种Predicate
是能够区分谓词和正则项。
这个尝试的问题是Struct
andPredicate
在结构上是等效的并且具有几乎相同的含义,但是我将无法编写在(Predicate "p" [])
和上都有效的函数——例如—— (Struct "p" [])
。
所以我的问题是:拜托,有没有更好的方法来编码我的谓词和术语,例如:
- 我能够区分类型签名中的谓词和术语;
- 支持嵌套谓词 like
p(q(1), r(q(3), q(4)))
; - 我可以编写将在谓词上统一工作的函数,而没有像解决方案#3 中的任何区别吗?
如果您需要任何进一步的说明,请随时向我询问。
非常感谢。