Skip to content

Instantly share code, notes, and snippets.

@chenzx
Created December 12, 2013 13:18
Show Gist options
  • Save chenzx/7927813 to your computer and use it in GitHub Desktop.
Save chenzx/7927813 to your computer and use it in GitHub Desktop.
领域专用语言实战
领域专用语言实战
跳转至: 导航、 搜索
目录
1 初识DSL
2 现实中的DSL
3 DSL驱动的应用程序开发
4 内部DSL实现模式
5 Ruby、Groovy、Clojure语言中的内部DSL设计
6 Scala语言中的内部DSL设计
7 外部DSL的实现载体
8 用Scala语法解析器组合子设计外部DSL
9 展望DSL设计的未来
10 附录A:抽象在领域建模中的角色
11 附录B:元编程与DSL设计
12 附录C:Ruby语言的DSL相关特性
13 附录D:Scala语言的DSL相关特性
14 附录E:Groovy语言的DSL相关特性
15 附录F:Clojure语言的DSL相关特性
16 附录G:多语言开发
初识DSL
现实中的DSL
Groovy方案:
newOrder.to.buy(100.shares.of('IBM')){
limitPrice 300
allOrNone true
valueAs {qty, unitPrice -> qty * unitPrice - 500}
实现:
methodMissing
Integer.metaClass.getShares = { -> delegate } //?
closure参数?
内部DSL实现手段
灵巧API
Guice例:binder.bind(Service.class).to(ServiceImpl.class).in(Scopes.SINGETON)
语法树(AST)操纵
类型化内嵌
Paul Hudak, 1998 Haskell
反射式元编程
Ruby Object#send()
运行时元编程
例:Rails(ActiveRecord?has_many belongs_to validates_xxx_of)
编译时元编程
LISP/Clojure宏、C宏、C++模板
外部DSL实现手段
简单的正则表达式替换,代码生成
XML
Xtext
Scala解析器组合子
DSL驱动的应用程序开发
new ScriptEngineManager().getEngineByName("groovy").eval( ... new SequenceInputStream(...)... ); //cast to List<?>
由于DSL脚本被一个单独的ClassLoader加载,与Java环境存在互操作问题
用Scala作为Java的包装器集成(GroovyClassLoader?)
p55 implicit def enrichAccount(acc: Account): AccountDSL = new AccountDSL(acc)
注意:implicit限制了词法作用域!
p57 accounts.filter(_ belongsTo "John S.").map(_.caclcInterest).filter(_>threshold).foldLeft(0.0)(_+_)
基于Spring 2.0+的集成*
内部DSL实现模式
装饰器
class TaxFeeDecorator extends Trade { ... }
Ruby例:
def with(*args)
args.inject(self) { |memo, val| memo.extend val }
yield self if block_given?
tr = Trade.new(...).with TaxFee, Commision (混入2个module!)
Groovy ObjectGraphBuilder?
ClassNameResolver*
Scala泛型groupBy
def groupBy[T <% Ordered[T]](f: TradedQuantity => T) = {
val m = new HashMap[T, Set[TradedQuantity ]] with MultiMap[T, TradedQuantity]
for( q <- quantities) m.addBinding (f(q), q)
m.keys.toList.sort(_<_).map( m.andThen(_.toList)) 靠
p94 类型化约束 trait Trade {
type A <: Trading
val account: A
生成式DSL:通过模板
Ruby:类方法、mixin
生成式DSL:通过宏
(defmacro with-account [acc & body]
`(cond
(nil? ~acc) (throw (IllegalArgumentException. "error1"))
(= (trading? ~acc) false) (throw (IllegalArgumentException. "error2"))
:else ~@body))
Ruby、Groovy、Clojure语言中的内部DSL设计
鸭子类型
p111 Groovy MOP?
CLojure类型提示(type hint)?
猴子补丁(Ruby开放类)
p124 Groovy知识点*
ExpandoMetaClass
closure和delegate
Category?
p132 redef
Scala语言中的内部DSL设计
trait
p149 只要用户定义好转换(implicit),Scala会在脚本的调用点插入必要的语义结构(.)
偏函数
val f: PartialFunction[Boolean, Int] = { case true => 100 }
模块(object)
map、foldLeft、foldRight
p172 Monad
unit
bind(flatMap -> for语法糖)
外部DSL的实现载体
表7.1 YACC/Lex Bison/Flex Antlr Coco/R JavaCC* Jikes*
p192 递归下降回溯分析器 PEG
记忆分析器(Packrat)
语义谓词分析器*
p194 Xtext
元模型?EString Eint ...(可以生成IDE插件??牛)
生成代码:Xpand模板 ?
用Scala语法解析器组合子设计外部DSL
常用的解析器组合子:
顺序 ~
选择性顺序 ~> <~
替代 |
函数应用 ^^ ^^^
p ^^ f
p ^^^ r(生成AST的叶子节点?)
p ^? (f, error)
重复
rep(p), p*
rep1(p), p+
repN(n,p)
rep1sep(p,sep), p+(sep)
p207 Newspeak语言:Self+SmallTalk?
包scala.util.parsing
abstract class Parser[+T] extends (Input => ParserResult[T])
sealed abstract class ParserResult[+T] { ... var next: Input } //跟踪下一个输入?
Success
Failure
object OrderDsl extends StandardTokenParsers { //import scala.util.parsing.combinator.syntactical._
lexical.reserved += ("to", "buy", ...)
lexical.delimiters += ("(", ")", ",")
lazy val order = items ~ account_spec
lazy val items = "(" ~> rep1sep(line_item, ",") <~ ")"
...
用Monad组合DSL分析器
def ~ [U](p: => Parser[U]): Parser[~[T,U]] = (for(a <- this; b <- p) yield new ~(a,b)).named("~")
LL(k)语法的packrat分析
通过使用一个带缓存能力的Reader:class PackratReader[+T](underlying: Reader[T]) extends Reader[T] { ... }
?packrat提供无扫描器的语法分析?
但:为了区分保留字和标识符,需要为文法补充一些作为消除歧义的额外信息
如果几个备选项开头部分有重合,应将匹配长度较长的备选项排在前面
SSI(结算常设规则?):用于指示特定交易应该在什么帐号上结算
p227~228 这个地方的代码例子有点复杂,跳过
p226 把分析器转为packrat的步骤:?
mixin PackratParsers(with语法)
给出Reader[Elem]的具体类型,作为对Input的定义
显式指定返回类型为PackratParser[...]
展望DSL设计的未来
p238 DSL工作台
Eclipse EMF
MPS
DSL版本化*
附录A:抽象在领域建模中的角色
作者多次强调,Scala的implicits比Ruby的monkey patching更好?
基于原型的OO
分离命令和查询*
STM*
附录B:元编程与DSL设计
附录C:Ruby语言的DSL相关特性
附录D:Scala语言的DSL相关特性
附录E:Groovy语言的DSL相关特性
附录F:Clojure语言的DSL相关特性
附录G:多语言开发
@jeffssss
Copy link

好精炼的总结方式,学习一下 ORZ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment