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

Cuneiform
编程范型纯函数式, 数据流程
设计者Jörgen Brandt
发行时间2013年,​11年前​(2013
当前版本
  • 3.0.5(2022年5月27日)[1]
编辑维基数据链接
类型系统简单类型
实现语言Erlang
操作系统Linux, Mac OS
许可证Apache许可证 2.0
文件扩展名.cfl
网站cuneiform-lang.org
启发语言
Swift (并行脚本语言)英语Swift (parallel scripting language)

概述

编辑

Cuneiform尝试拉近在科学工作流程系统如Apache Taverna英语Apache TavernaKNIME英语KNIMEGalaxy,与大规模数据分析程序模型如MapReducePig Latin之间的间隙,同时提供函数式编程语言的通用性。

Cuneiform是用分布式Erlang实现的。如果运行在分布式模态下,它导出一个遵循POSIX分布式文件系统,如GlusterCeph英语Ceph (software)#CephFS(用FUSE集成某个其他文件系统例如HDFS)。作为替代选择,Cuneiform脚本可以执行在HTCondor英语HTCondorApache Hadoop顶上[4][5][6][7]

Cuneiform受到了Peter Kelly的工作的影响,他提议函数式编程作为科学工作流程执行的模型[8]。 故而,Cuneiform不同于其他的基于数据流程编程的工作流程语言,如并行脚本语言Swift英语Swift (parallel scripting language)[9]

扩展软件集成

编辑

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

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

计划增加外界语言AWKgnuplot

类型系统

编辑

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

基础数据类型

编辑

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

记录和模式匹配

编辑

Cuneiform提供记录(结构)作为复合数据类型。下面的例子展示定义一个变量r,作为有两个字段a1a2的记录,第一个是字符串,而第二个是布尔值:

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

记录可以要么通过投影(projection)要么通过模式匹配来访问。下面的例子从记录r,提取两个字段a1a2

let a1 : Str = ( r|a1 );

let <a2 = a2 : Bool> = r;

列表和列表处理

编辑

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

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

列表可以通过forfold算子来处理。这里的for算子可以接受多个列表,来逐个元素的处置列表(类似于Racket中的for/listCommon Lisp中的mapcarErlang中的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程序允许fg的应用平行的运行,而h是有依赖的,它只在fg二者完成的时候可以开始:

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的构造中,fg的应用是独立的,因此可以并行运行:

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英语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英语HTCondor, Apache Hadoop Bash, BeanShell英语BeanShell, Common Lisp, MATLAB, GNU Octave, Perl, Python, R, Scala
2.2.x 2016年4月 Erlang HTCondor英语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英语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的实现语言从JavaErlang的迁移期间,持续使用了三年。求值不同于早期方式,解释器归约一个表达式,而非遍历一个静态图。在外表语法保持使用这段时期,解释器被形式化和简化,这导致了第一个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. ^ Release 3.0.5. 2022年5月27日 [2023年3月19日]. 
  2. ^ 存档副本. [2021-03-03]. (原始内容存档于2021-03-18). 
  3. ^ Brandt, Jörgen; Bux, Marc N.; Leser, Ulf. Cuneiform: A functional language for large scale scientific data analysis (PDF). Proceedings of the Workshops of the EDBT/ICDT. 2015, 1330: 17–26 [2021-03-03]. (原始内容 (PDF)存档于2020-02-17). 
  4. ^ Scalable Multi-Language Data Analysis on Beam: The Cuneiform Experience by Jörgen Brandt. Erlang Central. [28 October 2016]. (原始内容存档于2 October 2016). 
  5. ^ Bux, Marc; Brandt, Jörgen; Lipka, Carsten; Hakimzadeh, Kamal; Dowling, Jim; Leser, Ulf. SAASFEE: scalable scientific workflow execution engine (PDF). Proceedings of the VLDB Endowment. 2015, 8 (12): 1892–1895 [2021-03-03]. doi:10.14778/2824032.2824094. (原始内容 (PDF)存档于2020-11-25). 
  6. ^ 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. Biobankcloud: a platform for the secure storage, sharing, and processing of large biomedical data sets (PDF). The First International Workshop on Data Management and Analytics for Medicine and Healthcare (DMAH 2015). 2015 [2021-03-03]. (原始内容 (PDF)存档于2018-10-01). 
  7. ^ Scalable Multi-Language Data Analysis on Beam: The Cuneiform Experience. Erlang-factory.com. [28 October 2016]. (原始内容存档于2020-07-12). 
  8. ^ Kelly, Peter M.; Coddington, Paul D.; Wendelborn, Andrew L. Lambda calculus as a workflow model. 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. Workflows and extensions to the Kepler scientific workflow system to support environmental sensor data access and analysis (PDF). Ecological Informatics. 2010, 5 (1): 42–50 [2021-03-03]. doi:10.1016/j.ecoinf.2009.08.008. (原始内容 (PDF)存档于2022-02-25). 
  9. ^ Di Tommaso, Paolo; Chatzou, Maria; Floden, Evan W; Barja, Pablo Prieto; Palumbo, Emilio; Notredame, Cedric. Nextflow enables reproducible computational workflows. Nature Biotechnology. 2017, 35 (4): 316–319. PMID 28398311. doi:10.1038/nbt.3820. 
  10. ^ A Functional Workflow Language Implementation in Erlang (PDF). [28 October 2016]. (原始内容 (PDF)存档于2022-02-25). 
  11. ^ Brandt, Jörgen; Reisig, Wolfgang; Leser, Ulf. Computation semantics of the functional scientific workflow language Cuneiform. Journal of Functional Programming. 2017, 27. S2CID 6128299. doi:10.1017/S0956796817000119.