元计算的一个实际用例

元计算是我设计的太极语言中一个重要的特征。这里元计算指的是在编译时间运行从源语言代码编译后获得的目标语言代码。受到C语言中的预处理指令前缀#(#define,
#if-#else等)的启发,我选用#开头的一组符号作为各种元运算的算符。比如##expression 是编译时间运行expression, # if ...,
# let ...,  # while ..., # try ...
等将先对后续代码进行某种类似lisp的宏转换,然后在编译时间进行计算,通过这种转换,# if 会有C语言下的条件编译的效果,# let
等等也都具有各自的功能,因此某种程度上#是C语言的预处理指令通用化以后的一个算符,如果#后面不是这些特殊语句,而是一个普通的表达式,那么其效果与##相同。元算符#.的作用是让#.expression同时在编译时间和运行时间有效。

元计算可以有很大的威力,可以想象到很多应用的可能。以下例子,只是很多用途中的一种。

在下面的例子中,text是解析器正在解析的整个文本,cursor是当前全局解析位置,parserLineno和parserRow分别是全局行号和列号。

考虑到处理换行符号,匹配任意文字的解析函数可以这样写
literal = (string) -> 
start =
cursor; lineno = parserLineno; row = parserRow
for c in string
if
c==text[cur++]
if c==‘\n‘ then parserLineno++; parserRow = 0
else if
c==‘\r‘ then parserRow = 0; continue
else parserRow++
else cursor =
start; parserLineno = lineno; parserRow = row; return
true

但是在实际应用中,绝大多数情况下我们都不需要考虑换行符号,因此使用如下的函数就可以了。
literal2 = (string)
->
start = cursor; row = parserRow
for c in string
if
c==text[cursor++] then parserRow++
else cursor = start; parserRow = row;
return
true

或者更快捷的实现
literal2 = (string) -> if text[cursor...cursor+length]==string
then cursor += length; parserRow += length-1; true

下面是解析while语句的函数,作为例子,做了一些简化:
whileStatement = >
if literl(‘while‘)
and (test = parser.clause())? and literal(‘then‘) and (body=parser.block() or
parser.line())
return [‘while‘, test, body]

出于速度的原因,我们应该将上面whileStatement实现代码中的literal替换成literal2。
对于这样一个功能简单的小问题引入两个函数,无疑会增加API的数量,从文档提供和库用户的学习使用的角度来讲都是一种负担。另外仔细分析,上面的通用文字处理函数literal还有优化的空间,由此引出了下面第二种方案。

第二种方案
literal = (string) ->
i = 0; lineNumber = 0; length =
string.length
while c = string[i++]
if c==‘\n‘ then lineNumber++;
row = 0
else if c==‘\r‘ then _r = true; continue
else row++

if lineNumber==0
if _r then -> if text[cursor...cursor+length]==string
then cursor += length; parserRow += length-1; true
else -> if
text[cursor...cursor+length]==string then cursor += length; parserRow += length;
true
else -> if text[cursor...cursor+length]==string then cursor +=
length; parserLineno += lineNumber; parserRow += row; true

在此实现下,whileStatement的代码如下:
whileStatement = >
if
literal(‘while‘)() and (test = parser.clause())? and literal(‘then‘)() and
(body=parser.block() or parser.line())
return [‘while‘, test,
body]
然而,这样写并不能提升速度,反而会有性能损失,因为每次都必须要计算函数闭包。为了达到性能提升的目的,我们应该把对于的闭包计算提到函数之外:
因此应该这样写
while_
= literal(‘while‘); then_ = literal(‘then‘)

whileStatement = >
if while_() and (test = parser.clause())? and
then_() and (body=parser.block() or parser.line())
return [‘while‘, test,
body]

元计算派上用场:
这种情况正好是我设计的新语言的元计算能力的用武之地。
whileStatement = >
if
#(literal(‘while‘))() and (test = parser.clause())? and #(literal(‘then‘))() and
(body=parser.block() or parser.line())
return [‘while‘, test,
body]
元计算让我们鱼和熊掌兼得:同时拥有运行效率和编程效率。

元计算的一个实际用例,布布扣,bubuko.com

时间: 2024-10-22 08:55:23

元计算的一个实际用例的相关文章

小算法-计算下一个排列

2 8 5 3 1 1.从后往前,找到第一个逆序的数 pivot 2.从后往前,找到第一个比pivot大的数 change 3.交换 pivot 和 change的值 4.把pivot这个位置后面的数 reverse,就是 8 5 2 1变成 1 2 5 8 最终为3 1 2 5 8 #include <iostream> #include <vector> #include <algorithm> using namespace std; /* * num.begin

使用PHP计算上一个月的今天

一日,遇到一个问题,求上一个月的今天. 最开始我们使用 strtotime(“-1 month”) 函数求值,发现有一个问题,月长度不一样的月份的计算结果有误. 比如:2011-03-31,得到的结果是2011-03-03.我们先不追究什么问题,先看如何解决问题. 此时,想起PHP中有一个mktime函数,于是自己写了如下代码: echo date("Y-m-d H:i:s", mktime(date("G", $time), date("i",

Algs4-1.2.3编写一个Interval2D用例

1.2.3编写一个Interval2D用例,从命令行接受参数N.min和max.生成N个随机的2D间隔,其宽和高均匀地分布在单位正方形中的min和max之间.用StdDraw画出它们并打印出相关的间隔对的数量以及有包含关系的间隔对数量.解:相交是两个矩形区域有共点,包含是指一个矩形在一个矩形内,包含也是相交的一种情况.两个矩形相交并且一个矩形的三个顶点在另一个矩形区域内,那么两个矩形有包含关系.将下面的代码添加到Interval2D.java文件中,用来获取2D的左上角.左下角.右上角的坐标. 

Spring Ajax一个简单样例

配置不说了.要在前面helloworld的样例基础上弄. 相同在hello下新建ajax.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page isELIgnored ="false" %> <!DOCTYPE html PUBLIC "-//

java用毫秒数做日期计算的一个踩坑记录

错误示例: Date today = new Date(); Date nextMonth = new Date(today.getTime() + 30* 1000*60*60*24); println(today); println(nextMonth); Result:  Sat Sep 30 11:18:24 CST 2017 Sun Sep 10 18:15:37 CST 2017 代码说明:上面代码的目的是计算一个月后的日期,从结果发现明显是错误的(回到上个月去了) 原因分析:30*

hdu1011(树形背包)(提供一个特殊样例)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1011 Starship Troopers Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 23806    Accepted Submission(s): 6342 Problem Description You, the leader o

【Xcode学C-1】怎样用Xcode练习C语言,并练习一个输出样例,以及重要的注意事项

直接用Xcode学习C语言,为iOS开发打基础. (1)选择OS X >>> Application >>> Command Line Tool (2)输入产品名称,公司唯一标识.应用程序唯一标识=公司唯一标识+产品名称. 注意:公司唯一标识通常是域名倒过来写,如www.hellocation.com.那么写成com.hellocation. 注意:选择C语言.默认是OC.所以我们在学习OC的时候没有做不论什么动作. (3)进入程序后,点击main.c程序源文件,有一段

Android MVP模式简单介绍:以一个登陆流程为例

老的项目用的MVC的模式,最近完成了全部重构成MVP模式的工作,虽然比较麻烦,好处是代码逻辑更加清楚.简洁,流程更加清晰,对于后续版本迭代维护都挺方便.对于一些想要学习MVP模式的同学来讲,百度搜出来的好多都没法直接转化为项目里可以直接用的东西,所以这里正好拿出自己项目里已经用了的,你们可以直接用到自己的项目里.当然,不可能把所有项目代码在这里放出来,所以就拿登陆的流程出来,这个比较合适也比较常用. 1.先看下包结构: model:放一些bean类,以及网络处理类RetrofitManager,

PHP计算上一个月最后一天、当月最后一天、下一个月最后一天

上个月最后一天: $last_month_last_day = date('Y-m-t',strtotime('-1 month')); 当月最后一天: $first_day=date('Y-m-01',time()); $this_month_last_day=date("Y-m-d",strtotime("$first_day +1 month -1 day")); 下月最后一天: $first_day=date('Y-m-01',time()); $next_