专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »编程综合 » 编程语言的发展趋势及未来方向(2):声明式编程和DSL »正文

编程语言的发展趋势及未来方向(2):声明式编程和DSL

来源: 发布时间:星期三, 2010年5月26日 浏览:0次 评论:0
  这是Anders Hejlsberg(不用介绍这是谁了吧)在比利时TechDays 2010所做开场演讲由于最近我在博客上有关语言讨论比较多出于应景也打算将Anders演讲完整地听写出来在上部分中Anders指出语言本身在过去数十年里并没有明显发展并给出了他眼中编程语言发展趋势预测在现在第2部分中Anders将阐述声明式编程理念及DSL并演示C#中种内部 DSL形式:LINQ

  如果没有特别介绍说明所有文字都直接翻译自Anders演讲并使用我自己口语习惯表达出来对于Anders口误及反复等情况必要时在译文中自然也会进行忽略为了方便理解我也会将视频中关键部分进行截图而某些代码演示则会直接作为文章内容发表



  这里先从声明式(Declarative)编程谈起



  目前我们在编写软件Software时大量使用是命令式(Imperative)编程语言例如C#Java或是C等等这些语言特征在于写出代码除了表现出“什么(What)”是你想做事情的外更多代码则表现出实现细节也就是“如何(How)”完成工作这部分代码有时候多到掩盖了我们原来问题解决方案比如你会在代码里写for循环语句a等于bi加等等这体现出机器是如何处理数据首先这种做法让代码变得冗余而且它也很难让执行代码基础设施更聪明地判断该如何去执行代码当你写出这样命令是代码然后把编译后中间语言交给虚拟机去执行此时虚拟机并没有多少空间可以影响代码执行方式它只能根据指令条老老实实地去执行例如我们现在想要并行地执行就很困难了更高层次些信息已经丢失了这样我们只能在代码里给出“How”而不能体现出“What”信息

  有多种方式可以将“What”转化为更为“声明式”编程风格我们只要能够在代码中体现出更多“What”而不是“How”信息这样执行环境便可以更加聪明地去适应当前执行要求例如它可以决定投入多少CPU进行计算当前硬件是什么样等等



  我的前提到过现在有两种比较重要成果是DSL(Do Specic Language领域特定语言)个则是式编程

  其实DSL不是什么新鲜玩意儿我们平时直在用类似东西比如SQLCSS正则表达式可能更加专注于个方面例如MathematicaLOGO等等这些语言目标都是特定领域和的相对则是GPPL(General Purpose Programming Language通用目编程语言)



  对于DSL而言其实并没有个明确定义在这里我也不打算为它下个定义例如UML甚至根本没有特定语法不过我这里会谈些我觉得比较重要东西



  Martin Fowler提出DSL应该分为外部DSL及内部DSL两种我认为这种划分方式还是比较有意义外部DSL是自我包含语言它们有自己特定语法、解析器和词法分析器等等它往往是种小型编程语言甚至不会像GPPL那样需要源文件和的相对则是内部DSL内部DSL其实更像是种别称它代表类特别API 及使用模式这里我会给你们看些举例



  这些是我们平时会遇到些外部DSL如这张幻灯片上表现XSLTSQL或是Unix脚本外部DSL特点是你在构建这种DSL时其实扮演是编程语言设计者角色这个工作并不会交给普通人去做外部DSL般会直接针对特定领域设计而不考虑其他东西James Gosling曾经说过这样每个配置文件最终都会变成门编程语言开始可能只会用它表示点点东西然后慢慢你便会想要些规则而这些规则则变成了表达式可能你还会定义变量进行条件判断等等而最终它就变成了种奇怪编程语言这样情况屡见不鲜

  事实上现在有些公司也在关注DSL开发例如以前在微软工作Charles Simonyi提出了Intentional Programming概念还有个叫做JetBrains公司提供个叫做MPS(Meta Programming )产品最近微软也提出了自己Oslo项目而在Eclipse世界里也有个叫做Xtext东西所以其实在这方面现在也有不少人在尝试

  我在观察外部DSL时往往会关注它语法到底提供了多少空间例如种XML方言利用XML方言好处在于有不少现成工具可用这样可以更快地定义自己语法



  而内部DSL正像我的前说那样它其实只是系列特别API及使用模式别称这里则是些LINQ查询语句Ruby _disibledevent=>

  现在我会花几分钟时间演示下我所创建DSL也就是LINQ我相信你们也已经用过不少LINQ了不过这里我还是快速展示下我所表达更为“声明式”编程方式

public  Product 
{ 
  public  ProductID { get; ; } 
  public  ProductName { get; ; } 
  public  CategoryName { get; ; } 
  public  UnitPrice { get; ; } 
 
  public  List<Product> GetProducts { /* ... */ } 
} 
 
public partial  _Default : .Web.UI.Page 
{ 
  protected void Page_Load(object sender, EventArgs e) 
  { 
    List<Product> products = Product.GetProducts; 
 
    List<Product> result =  List<Product>; 
    foreach (Product p in products) 
    { 
       (p.UnitPrice > 20) result.Add(p); 
    } 
 
    GridView1.DataSource = result; 
    GridView1.DataBind; 
  } 
}


  这里有许多Product对象那么现在我要筛选出所有单价大于20那些再把他们显示在个GridView中传统做法就是这样我先得到所有Product对象然后foreach遍历每个对象再判断每个对象单价最终把数据绑定到GridView里运行这个……(打开页面)这就是就能得到结果

  好那么现在我要做些稍微复杂事情可能我不是要展示单价超过20Product对象而是要查看每个分类中究竟有多少个单价超过20对象然后根据数量进行排序如果不用DSL完成这个工作那么我可能会先定义个对象来表示结果:

 Grouping 
{ 
  public  CategoryName { get; ; } 
  public  ProductCount { get; ; } 
}


  这是个表示分组对象用于保存分类名称和产品数量然后我们就会写些十分丑陋代码:

Dictionary<, Grouping> groups =  Dictionary<, Grouping>; 
foreach (Product p in products) 
{ 
   (p.UnitPrice >= 20) 
  { 
     (!groups.ContainsKey(p.CategoryName)) 
    { 
      Grouping r =  Grouping; 
      r.CategoryName = p.CategoryName; 
      r.ProductCount = 0; 
      groups[p.CategoryName] = r; 
    } 
    groups[p.CategoryName].ProductCount; 
  } 
} 
 
List<Grouping> result =  List<Grouping>(groups.Values); 
result.Sort(delegate(Grouping x, Grouping y) 
{ 
   
    x.ProductCount > y.ProductCount ? -1 : 
    x.ProductCount < y.ProductCount ? 1 : 
    0; 
});


  我先创建个新字典用于保存分类名称到分组对应关系然后我遍历每个Product对象对于每个单价大于20对象如果字典中还没有保存对应分组则创建然后将数量加然后为了排序Sort思路方法于是我要提供个委托作为排序思路方法然后blablablabla……执行的后……(打开页面)我自然可以得到想要结果

  但是首先这些代码写起来需要花费些时间很显然然后仔细观察你会发现这写代码几乎都是在表示“How”而“What”基本已经丢失了假设我离开了现在新来了员要维护这段代码他会需要点时间才能完整理解这段代码他无法直接看清代码目标

  不过如果这里我们使用DSL也就是LINQ就像这样:

var result = products 
  .Where(p => p.UnitPrice >= 20) 
  .GroupBy(p => p.CategoryName) 
  .OrderByDescending(g => g.Count) 
  .Select(g =>  { CategoryName = g.Key, ProductCount = g.Count });


  products……先Where……blablabla……再GroupBy等等由于我们这里可以使用DSL来表示高阶术语用以体现我们想做事情于是这段代码则更加关注于“What”而不是“How”我这里不会明确地指示我想要过滤方式我也不会明确地说我要建立字典和分类这样基础结构就可以聪明地或者说更加聪明地去确定具体执行方式你可能比较容易想到我们可以并行地执行这段代码我没有显式地指定做事方式我只是表示出我意图

  我们打开页面……(打开页面)很显然我们得到了相同结果

  这里比较有趣内部DSL是如何设计进C#语法中为此我们为C# 3.0添加了系列特性例如Lambda表达式扩展思路方法类型推断等等这些特性统起来的后我们就可以设计出更为丰富API组合的后便成为种内部DSL就像这里LINQ查询语言

  除了使用API形式的外我们还可以这样做:



var result = 
  from p in products 
  where p.UnitPrice >= 20 
  group p by p.CategoryName o g 
  orderby g.Count descending 
  select  { CategoryName = g.Key, ProductCount = g.Count };


  编译器会简单地将这种形式转化为前种形式不过这里我认为有意思地方在于你完全可以创建门和领域编程语言完全无关语法然后等这种语法和API变得流行且丰富起来的后再来创种新表现形式就如这里LINQ查询语法我颇为中意这种语言设计交流方式

  OK现在我们回到下面内容

  文章来源:http://blog.zhaojie.me/2010/04/trends-and-future-directions-in-programming-languages-by-anders-2-declarative-programming-and-dsl.html



标签:
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: