Lucid是数据流程编程语言,设计用来实验非冯·诺伊曼编程模型。它是William W. Wadge和Edward A. Ashcroft在1976年设计的,并描述于1985年的书籍《Lucid, the Dataflow Programming Language》。但是,数据流程释义在Lucid的演变方向上有着重要的影响。
细节
Lucid从ISWIM继承了where子句作为自己的块结构,从POP-2继承了数据类型。在Lucid中,每个表达式中的变量,都要先在表达式自身的where子句中寻找对应的变量定义,包含仍未约束的变量的表达式,在继续进行(proceed)之前,要等待直到这个变量已经被约束,即等待从输入中获取变量的值。一个表达式如x + y,在返回这个表达式的输出之前,将等待直到x和y二者都成为约束的。这样有一个重要结果,避免了更新有关值的显式的逻辑,导致了相较于主流语言的先声明再引用方式有大量的代码简约。
在Lucid中每个变量都是值的流(stream)。算子fby(followed by的助忆码),定义了在前一个表达式之后会出现什么。表达式n = 1 fby n + 1使用fby定义了一个流n,在这个实例中,这个流产生序列[1,2,3,...]。在流中的值,可以通过如下这些算子来寻址取用,假定x是用到的变量:
*first x - 取回在流x中的第一个值。每次求值这个表达式都得到同样这个值。
*x - 取回在流x中当前值。
*next x - 取回在流x中当前值的下一个值。
*x asa p - 如果p提供了一个"true"值,则立刻(as soon as)提供x,否则在下一个x和下一个p上继续进行此运算操作。每次求值这个表达式都得到同样这个值。可以想像为它根据控制流p,从流x选取出第一个已经符合条件的值。
*x whenever p - 如果p提供了一个"true"值,则提供x;接着在下一个x和下一个p上继续进行此运算操作。可以想像为它根据控制流p,从流x过滤出符合条件的所有值。它可以写为助记码wvr。
*x upon p - 提供x,如果p提供了一个"true"值,则在下一个x和下一个p上继续进行此运算操作,否则在这个x和下一个p上继续进行此运算操作。可以想像为它根据控制流p,在符合条件时放行流x的下一个值,在不符合条件时以重复当前值的方式滞留流x。
*x attime i - 将流i中的值作为流p中值的位次索引,依次从i取得索引选择流x中指定位次的值。可以想像为它根据索引流i,对流x进行了选取和重组。
*X is current x - 将流x的当前值保存在X变量中。每次求值X时都得到同样的这个值。典型用于嵌套的内层迭代,它不能直接使用x而导致这个流的当前值顺序前进的情况下,比如后面例子中的指数函数程序等。
计算是通过定义作用在数据的时变流上的过滤器或变换函数来完成的。涉及多个流的函数和运算操作采用逐点(pointwise)释义比如:f(x,y) = [f(x0,y0),f(x1,y1),f(x2,y2),...],在后面例子中进行二个流的归并和串接时,因而在条件表达式if p then x else y fi中需要通过upon对要操作的流进行预处理。
数据结束(end of data)对象用预定义特殊标识符eod表示,iseod eod将返回"true",此外所有的对eod的运算操作都产生eod。错误对象用预定义特殊标识符error表示。index是预定义变量,它是以0开始的自然数序列。此外预定义变量还有true = "true"、false = "false"等。
例子
序列的总和
total
where
total = 0 fby total + x
end
累积移动平均
running_avg
where
sum = first(input) fby sum + next(input);
n = 1 fby n + 1;
running_avg = sum / n;
end
阶乘
fac
where
n = 0 fby (n + 1);
fac = 1 fby (fac * (n + 1));
end
斐波那契数列
fib
where
fib = 0 fby (1 fby fib + next fib);
end
指数函数
指数函数的幂级数e^x = 1+ \sum_{n = 1}^{\infty} {x^n \over n!} = 1 + x + {x^2 \over 2!} + {x^3 \over 3!} + \cdots的前10项:
expsum asa next i eq 10
where
X is current x;
i = next index;
term = 1 fby (term / i) * X;
expsum = 0 fby expsum + term;
end
均方根
在下面均方根程序中的平方根计算使用了。
sqroot(avg(square(a)))
where
square(x) = x*x;
avg(y) = mean
where
n = 1 fby n+1;
mean = first y fby mean + d;
d = (next y - mean)/(n+1);
end;
sqroot(z) = approx asa err
素数
prime
where
prime = 2 fby (n whenever isprime(n));
n = 3 fby n+2;
isprime(n) = not(divs) asa divs or prime*prime > N
where
N is current n;
divs = N mod prime eq 0;
end;
end
数据流程图
:
漢明數
计算升序的正规数的算法经由戴克斯特拉得以流行,有关问题叫做“汉明问题”。Dijkstra计算这些数的想法如下:
- 汉明数的序列开始于数1。
- 要加入序列中的数有下述形式:2h,3h,5h,这里的h是序列已有的任意的汉明数。
- 因此,可以生成最初只有一个1的序列H,并接着序列2H,3H,5H,并以此类推。
hamming
where
h = 1 fby merge(merge(2 h, 3 h), 5 * h);
merge(x,y) = if xx
注意这个程序中归并函数中的upon条件能够起到二个流中可能存在的相同值在结果中只出现一个的效果。
数据流程图
:
快速排序
下面程序实现了霍尔的快速排序算法,将序列划分为小于基准值(pivot)的元素和不小于它的元素的两个子序列,然后递归的排序这两个子序列,再将结果的两个排好序的子序列串接起来。
qsort(a) = if iseod(first a) then a else follow(qsort(b0), qsort(b1)) fi
where
p = a
数据流程图
+--------> whenever -----> qsort ---------+
| ^ |
| | |
| not |
| ^ |
|---> first | |
| | | |
| V | |
|---> less ---+ |
| | |
| V V
---+--------> whenever -----> qsort -----> follow -----> if-then-else ----->
| ^ ^
| | |
+--------> next ----> first ------> iseod --------------+ |
| |
+------------------------------------------------------------+
引用
外部链接
*[https://github.com/mwmarkland/plucid pLucid]
*[http://c2.com/cgi/wiki?LucidLanguage Language overview]
*[http://www.haskell.org/haskellwiki/Lucid Lucid page of HaskellWiki]
评论 (0)