**Cuneiform**是用于大规模科学数据分析的开源工作流程语言（英语：）。
它是促进并行计算的静态类型的纯函数式编程语言。它的特征是有个全功能的外界函数接口（英语：），允许用户集成来自很多外部编程语言的软件。Cuneiform在组织层面上提供了一些设施，如条件分支和通用递归，使其具有图灵完备性。

概述
--

Cuneiform尝试拉近在科学工作流程系统如Apache Taverna（英语：）、KNIME（英语：）或Galaxy，与大规模数据分析程序模型如MapReduce或Pig Latin之间的间隙，同时提供函数式编程语言的通用性。

Cuneiform是用分布式Erlang实现的。如果运行在分布式模态下，它导出一个遵循POSIX的分布式文件系统，如Gluster或Ceph（英语：）（用FUSE集成某个其他文件系统例如HDFS）。作为替代选择，Cuneiform脚本可以执行在HTCondor（英语：）或Apache Hadoop顶上。

Cuneiform受到了Peter Kelly的工作的影响，他提议函数式编程作为科学工作流程执行的模型。
故而，Cuneiform不同于其他的基于数据流程编程的工作流程语言，如并行脚本语言Swift（英语：）。

扩展软件集成
------

外部工具和库（比如R或Python库）是通过外界函数接口（英语：）来集成的。通过它可以组合，比如允许通过snippet节点使用外部软件的KNIME（英语：），或为集成Java软件提供BeanShell（英语：）服务的Apache Taverna（英语：）。通过定义采用外界语言的任务，就可能使用一个外部工具或库的API。这种方式下，工具可以直接集成而不需要写包装器或重新实现工具。

目前支持的外界编程语言有：

* Bash
* Elixir
* Erlang
* Java
* JavaScript
* MATLAB
* GNU Octave
* Perl
* Python
* R
* Racket

计划增加外界语言AWK和gnuplot。

类型系统
----

Cuneiform提供简单的、静态检查的类型系统。虽然Cuneiform提供列表作为复合数据类型，它省略了传统的列表访问子（`head`和`tail`），以避免在访问空列表时，可能引起的运行时间错误的可能性。转而列表只能通过在其上`map`或`fold`，以全有或全无方式访问。此外，Cuneiform（在组织层面）省略了算术，这排除了除以零的可能性。省略任何的部份定义运算，允许保证运行时间错误只能在外界代码中引发。

### 基础数据类型

Cuneiform提供的基础数据类型有布尔值、字符串和文件。这里的文件被用来以任意格式在外界函数之间交换数据。

### 记录和模式匹配

Cuneiform提供记录（结构）作为复合数据类型。下面的例子展示定义一个变量`r`，作为有两个字段`a1`和`a2`的记录，第一个是字符串，而第二个是布尔值：

```
let r : <a1 : Str, a2 : Bool> =
  <a1 = "my string", a2 = true>;

```

记录可以要么通过投影（projection）要么通过模式匹配来访问。下面的例子从记录`r`，提取两个字段`a1`和`a2`：

```
let a1 : Str = ( r|a1 );

let <a2 = a2 : Bool> = r;

```

### 列表和列表处理

进一步的，Cuneiform提供列表作为复合数据类型。下面的例子展示定义一个变量`xs`，作为一个有三个元素的一个文件：

```
let xs : [File] =
 ['a.txt', 'b.txt', 'c.txt' : File];

```

列表可以通过`for`和`fold`算子来处理。这里的`for`算子可以接受多个列表，来逐个元素的处置列表（类似于Racket中的`for/list`、Common Lisp中的`mapcar`或Erlang中的`zipwith`）。

下面的例子展示如何在一个单一的列表上`map`，结果是一个文件列表：

```
for x <- xs do
  process-one( arg1 = x )
  : File
end;

```

下面的例子展示如何`zip`两个列表，结果也是一个文件列表：

```
for x <- xs, y <- ys do
  process-two( arg1 = x, arg2 = y )
  : File
end;

```

最后，列表可以使用`fold`算子来做聚集。下面的例子合计一个列表的元素：

```
  fold acc = 0, x <- xs do
    add( a = acc, b = x )
  end;

```

并行执行
----

Cuneiform是纯函数式语言，就是说它不支持可变引用。作为结论，它可以使用独立子项，将一个程序分解成可并行的各部份。Cuneiform调度器分布这些部份到做工节点。此外，Cuneiform采用传名调用求值策略，值只在它对计算结果有贡献时计算。最后，外界函数应用是记忆化的，用来加速包含以前推导结果的计算。

例如，下列Cuneiform程序允许`f`和`g`的应用平行的运行，而`h`是有依赖的，它只在`f`和`g`二者完成的时候可以开始：

```
-{}-let output-of-f : File = f();
let output-of-g : File = g();

h( f = output-of-f, g = output-of-g );
```

下列Cuneiform程序通过将函数`f`映射到一个三元素列表，创建了三个并行应用：

```
-{}-let xs : [File] =
  ['a.txt', 'b.txt', 'c.txt' : File];

for x <- xs do
  f( x = x )
  : File
end;
```

类似的，在记录`r`的构造中，`f`和`g`的应用是独立的，因此可以并行运行：

```
let r : <a : File, b : File> =
 <a = f(), b = g()>;

```

例子
--

下面是一个hello-world脚本：

```
def greet( person : Str ) -> <out : Str>
in Bash \*{
  out="Hello $person"
}\*

( greet( person = "world" )|out );

```

这个脚本定义了采用Bash的一个任务`greet`，它对其字符串实际参数`person`预加上`"Hello "`。这个函数产生具有一个单一字符串字段的记录`out`。应用`greet`，绑定实际参数`person`到字符串`"world"`，产生记录`<out = "Hello world">`。将这个记录投影为它的字段`out`，求值出字符串`"Hello world"`。

可以通过定义采用Bash的一个任务来集成命令行工具：

```
def samtoolsSort( bam : File ) -> <sorted : File>
in Bash \*{
  sorted=sorted.bam
  samtools sort -m 2G $bam -o $sorted
}\*

```

在这个例子中定义了任务`samtoolsSort`。它调用了工具SAMtools（英语：），处置一个BAM格式的输入文件，并产生一个排序了也是BAM格式的输出文件。

发行历史
----

| 版本 | 出现日期 | 实现语言 | 发布平台 | 外界语言 |
| --- | --- | --- | --- | --- |
| 1.0.0 | 2014年5月 | Java | Apache Hadoop | Bash, Common Lisp, GNU Octave, Perl, Python, R, Scala |
| 2.0.x | 2015年3月 | Java | HTCondor（英语：）, Apache Hadoop | Bash, BeanShell（英语：）, Common Lisp, MATLAB, GNU Octave, Perl, Python, R, Scala |
| 2.2.x | 2016年4月 | Erlang | HTCondor（英语：）, Apache Hadoop | Bash, Perl, Python, R |
| 3.0.x | 2018年2月 | Erlang | 分布式Erlang | Bash, Erlang, Java, MATLAB, GNU Octave, Perl, Python, R, Racket |

在2016年4月，Cuneiform的实现语言从Java切换成了Erlang，并且在2018年2月，它的主要发布执行平台从Apache Hadoop变更为分布式Erlang。此外，从2015年到2018年，HTCondor（英语：）曾被作为可替代执行平台来维护。

Cuneiform的外表语法修订过两次，这反映在主版本号上。

### 版本1

在2014年5月发布的最初草案中，Cuneiform密切关联于Make，它构造解释器在执行期间要遍历的静态数据依赖图。与后来版本的主要区别，是缺乏条件、递归或静态类型检查。区分文件和字符串，是通过同波浪号`~`形成一个单一引用的字符串。脚本的查询表达式，通过`target`关键字来介入。Bash是缺省外界语言。函数应用必须使用`apply`形式来完成，它接受`task`作为第一个关键字实际参数。一年之后，这种外表语法被一种精简却类似的版本所替代。

下面的例子脚本从一个FTP服务器下载一个参考genome：

```
declare download-ref-genome;

deftask download-fa( fa : ~path ~id ) *{
    wget $path/$id.fa.gz
    gunzip $id.fa.gz
    mv $id.fa $fa
}*

ref-genome-path = ~'ftp://hgdownload.cse.ucsc.edu/goldenPath/hg19/chromosomes';
ref-genome-id = ~'chr22';

ref-genome = apply(
    task : download-fa
    path : ref-genome-path
    id : ref-genome-id
);

target ref-genome;

```

### 版本2

基于Swing的编辑器和Cuneiform 2.0.3的REPL
Cuneiform外表语法的第二个草案，首次发表于2015年3月，在Cuneiform的实现语言从Java到Erlang的迁移期间，持续使用了三年。求值不同于早期方式，解释器归约一个表达式，而非遍历一个静态图。在外表语法保持使用这段时期，解释器被形式化和简化，这导致了第一个Cuneiform的语义规定。语法特征是有了条件。但是，布尔值被编码为列表，再度利用空列表为布尔值`false`，非空列表为布尔值`true`。递归后来作为形式化的副产品而增加。但是，静态类型检查，只在后来的版本3中介入。

下列脚本解压一个压缩文件，并把它分解为大小均匀的划分：

```
deftask unzip( <out( File )> : zip( File ) ) in bash *{
  unzip -d dir $zip
  out=`ls dir | awk '{print "dir/" $0}'`
}*

deftask split( <out( File )> : file( File ) ) in bash *{
  split -l 1024 $file txt
  out=txt*
}*

sotu = "sotu/stateoftheunion1790-2014.txt.zip";
fileLst = split( file: unzip( zip: sotu ) );

fileLst;

```

### 版本3

Cuneiform外表语法的当前版本，比较于早期的草案，是尝试拉近与主流函数式编程语言的间隙。它的特征是简单的静态检查的类型系统，并在列表之外介入记录作为第二个复合数据结构类型。布尔值独立为基础数据类型。

下列脚本解包一个文件，结果为一个文件列表：

```
def untar( tar : File ) -> <fileLst : [File]>
in Bash *{
  tar xf $tar
  fileLst=`tar tf $tar`
}*

let hg38Tar : File =
  'hg38/hg38.tar';

let <fileLst = faLst : [File]> =
  untar( tar = hg38Tar );

faLst;

```

引用
--

1. ↑ .  [2021-03-03]. （原始内容存档于2021-03-18）.
2. ↑  Brandt, Jörgen; Bux, Marc N.; Leser, Ulf.  (PDF). Proceedings of the Workshops of the EDBT/ICDT. 2015, **1330**: 17–26  [2021-03-03]. （原始内容 (PDF)存档于2020-02-17）.
3. ↑ . Erlang Central.  [28 October 2016]. （原始内容存档于2 October 2016）.
4. ↑  Bux, Marc; Brandt, Jörgen; Lipka, Carsten; Hakimzadeh, Kamal; Dowling, Jim; Leser, Ulf.  (PDF). Proceedings of the VLDB Endowment. 2015, **8** (12): 1892–1895  [2021-03-03]. doi:10.14778/2824032.2824094. （原始内容 (PDF)存档于2020-11-25）.
5. ↑  Bessani, Alysson; Brandt, Jörgen; Bux, Marc; Cogo, Vinicius; Dimitrova, Lora; Dowling, Jim; Gholami, Ali; Hakimzadeh, Kamal; Hummel, Michael; Ismail, Mahmoud; Laure, Erwin; Leser, Ulf; Litton, Jan-Eric; Martinez, Roxanna; Niazi, Salman; Reichel, Jane; Zimmermann, Karin.  (PDF). The First International Workshop on Data Management and Analytics for Medicine and Healthcare (DMAH 2015). 2015  [2021-03-03]. （原始内容 (PDF)存档于2018-10-01）.
6. ↑ . Erlang-factory.com.  [28 October 2016]. （原始内容存档于2020-07-12）.
7. ↑  Kelly, Peter M.; Coddington, Paul D.; Wendelborn, Andrew L.. Concurrency and Computation: Practice and Experience. 2009, **21** (16): 1999–2017. doi:10.1002/cpe.1448. 
Barseghian, Derik; Altintas, Ilkay; Jones, Matthew B.; Crawl, Daniel; Potter, Nathan; Gallagher, James; Cornillon, Peter; Schildhauer, Mark; Borer, Elizabeth T.; Seabloom, Eric W.  (PDF). Ecological Informatics. 2010, **5** (1): 42–50  [2021-03-03]. doi:10.1016/j.ecoinf.2009.08.008. （原始内容 (PDF)存档于2022-02-25）.
8. ↑  
Di Tommaso, Paolo; Chatzou, Maria; Floden, Evan W; Barja, Pablo Prieto; Palumbo, Emilio; Notredame, Cedric.. Nature Biotechnology. 2017, **35** (4): 316–319. PMID 28398311. doi:10.1038/nbt.3820.
9. ↑   (PDF).  [28 October 2016]. （原始内容 (PDF)存档于2022-02-25）.
10. ↑  
Brandt, Jörgen; Reisig, Wolfgang; Leser, Ulf.. Journal of Functional Programming. 2017, **27**. S2CID 6128299. doi:10.1017/S0956796817000119.


|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 

| * 
* 论
* 编
程序设计语言 |
| --- |
|  |
| 按范型 | 

|  |  |
| --- | --- |
| 过程式 | 
* FORTRAN
* COBOL
* ALGOL 60
* BASIC
	+ QB64（英语：）
* PL/I
* MUMPS（英语：）
* ALGOL 68
* Forth
* Pascal
	+ Turbo Pascal
* C
* Modula-2
* Ada 83
* occam
* Oberon
* Go
* Zig
* Carbon

 |
|  |
| 面向对象 | 
* Simula 67
* Smalltalk
* C++
* Objective-C
* Eiffel
* Object Pascal
	+ Delphi
* Self
* CLOS
* Visual Basic
	+ Gambas
* Ada 95
* Java
* C#
	+ Vala
* Fantom（英语：）
* Crystal（英语：）

 |
|  |
| 多范型 | 
* Modula-3
* Dylan
* Python
* Lua
* JavaScript
* Ruby
* D
* Factor
* Scala
* F#
	+ F\*
* Haxe
* Dafny（英语：）
* Nim
* Rust
* Dart
* Julia
* Swift
* Ballerina（英语：）
* Bosque（英语：）

 |
|  |
| 函数式 | 

|  |
| --- |
| 
* LISP
	+ Scheme
	+ Common Lisp
	+ Clojure
* Logo
* APL/J
* ML
	+ Standard ML
	+ OCaml
* Erlang
	+ Elixir
* Haskell
	+ Curry
* SAC
* Agda
* Idris
* Pure（英语：）
* jq（英语：）
* Cuneiform

 |

 |
|  |
| 逻辑式 | 
* Prolog
* Datalog
* Mercury
* AnsProlog

 |

 |
|  |
| 脚本语言 | 

|  |  |
| --- | --- |
| 动态语言 | 
* SNOBOL
* Icon
* REXX
* Perl
	+ Raku
* Tcl/Tk
* CLOS
* newLISP
* Python
* Lua
* Ruby
* PHP
	+ Hack
* REBOL
	+ Red（英语：）
* Io
* Julia

 |
|  |
| Shell语言 | 
* Unix shell
	+ sh
	+ csh/tcsh
	+ ksh
	+ bash
	+ ash
	+ zsh
	+ fish
* sed
* AWK
* PowerShell

 |
|  |
| ECMA-262 | 
* ECMAScript
	+ JavaScript
	+ Node.js/Deno
* CoffeeScript/LiveScript（英语：）
* TypeScript
* Elm
* PureScript
* Reason

 |

 |
|  |
| 特定平台 | 

|  |  |
| --- | --- |
| .NET | 
* C#
* C++/CLI
* F#
* PowerShell
* VB.NET
* Small Basic

 |
|  |
| JVM | 
* Java
	+ AspectJ（英语：）
* Scala
* Clojure
* Groovy
* Kotlin

 |

 |
|  |
| 特定领域 | 

|  |  |
| --- | --- |
| 科学计算 | 
* Speakeasy（英语：）
* IDL
	+ GDL
* Maxima
* Maple
* MATLAB
	+ Octave
	+ Scilab
* Wolfram
* R
* Yorick（英语：）
* SageMath
* Julia

 |
|  |
| GPU计算 | 
* GLSL
* HLSL
* OpenCL
* CUDA
* Futhark

 |
|  |
| 数据查询 | 
* SQL
	+ PL/SQL
	+ T-SQL
	+ SQL/PSM（英语：）
* xBase（英语：）
* XPath
* XQuery（英语：）
* GraphQL

 |
|  |
| 可视化 | 
* Simulink
* LabVIEW
* Orange（英语：）
* KNIME（英语：）
* Scratch
	+ Snap!
* Power Fx

 |
|  |
| 传媒设计 | 
* SuperCollider
* Pure Data
* Processing
* ChucK

 |

 |
|  |
| 其它 | 
* 汇编语言
* make
* PostScript
* XSLT
* WebAssembly

 |
|  |
| 
* 分类 目录
* 列表级条目 列表
* 历史
* 比较（英语：）
* 时间线（英语：）

 |

 |