pulp版本有什么不同
深度神经网络的属性推理,下面一起来看看本站小编慕测科技给大家精心整理的答案,希望对您有帮助
D. Gopinath, H. Converse, C. Pasareanu and A. Taly, "Property Inference for Deep Neural Networks," 2019 34th IEEE/ACM International Conference on Automated Software Engineering (ASE), San Diego, CA, USA, 2019, pp. 797-809, doi: 10.1109/ASE.2019.00079.
我们提出了自动推断前馈神经网络的形式属性的技术。据我们观察,前馈神经网络的逻辑有很大一部分是通过其神经元的激活状态来捕获的。我们提出了基于神经元决策的模式提取模式,通过将这些神经元的决策作为前提条件,来推理某些输出属性,例如,最终的预测类别。我们提出了提取输入属性的技术,在输入空间上编码来标记给定的输出属性和层属性的谓词,代表在隐藏层中捕获的网络属性,最终推理期望的输出结果。我们将我们的技术应用在 MNIST 和 ACASXU 上的网络。我们的实验强调了推理属性在各种任务中的应用,如解释预测、提供鲁棒性保证、简化证明和网络提炼等。
深度神经网络(DNNs)已经成为解决复杂计算任务的强大机制,在执行这些任务时取得了较为满意的效果,有时甚至超过了人类的能力。然而,DNNs 的使用越来越多的同时,也带来了一些安全和可靠性方面的问题。造成这种结果的有诸多因素,其中包括缺乏鲁棒性。众所周知,包括经过高度训练的 DNNs 在内的网络,很容易受到对抗性扰动的影响。对输入的微小(几乎是不可感知的)变化会导致错误分类。如果在自动驾驶的感知模块中使用这样的分类器,网络受对抗性图像的干扰所导致的错误决策会产生灾难性的后果。DNNs 还存在着缺乏可解释性的问题:人们不太了解网络为什么会做出某种预测,这阻碍了 DNNs 在安全关键领域的应用,如司法、银行、医学等。最后,在设计神经网络时,神经网络只从实例中学习,往往没有高层次的需求规范,这阻碍了神经网络具有严格的逻辑推理。在设计更传统的安全攸关系统时,这种逻辑性是必要的。
在本文中,我们提出了自动推断前馈神经网络的形式属性的技术,这些属性的形式为 Pre ? Post。Post 是一个后置条件,说明所期望的输出行为,例如,网络的预测结果是某一具体的类别。本文基于输入属性开展了研究。它编码了输入空间中的谓词,暗示了给定的输出属性。此外,本文还进一步研究了层属性,它将在中间层观察到的具有共同特征的输入进行分组,最终影响了网络的输出行为。
设置网络属性是构建网络的必要前置过程,该行为会导致诸多结果。在本文中,我们推断出 DNN 中神经元的决策模式所对应的属性。这种模式规定了不同层中哪些神经元处于激活或未激活状态。对于实现 ReLU 激活函数的神经元,这相当于神经元的输出是大于零(激活)还是等于零(未激活)。对于其他更复杂的特性(例如,使用一个正阈值而不是零的激活函数,在神经元值上使用线性组合),这些都是留待以后的工作中研究。
我们定义了基于模式的输入属性,这些模式约束了直到中间层的所有神经元的激活状态(激活或未激活)。这样的模式在输入空间中形成了凸状谓词。使用凸函数的特性在此处是很有必要的,因为它使推断出的属性很容易被可视化且具有较强的解释性。此外,凸型谓词可以用现有的线性编程求解器有效地求解。类似地,我们基于约束中间层激活状态的模式来定义层属性。层属性的模式定义了中间层值上的凸区域,可以表示为输入空间中的凸区域的联合。
研究决策模式的另一个动机是这类似于程序分析中的路径约束。不同的神经元决策模式也能捕捉到不同的 DNN 行为。我们认为,根据决策模式提取出简洁的输入输出属性是可行的。这些属性共同解释了网络的行为,可以作为网络的形式化规范。我们提出了两种提取网络属性的技术。我们的第一种技术是基于迭代的决策模式,同时利用现有的决策程序。我们使用了决策程序 Reluplex,旨在证明前馈式 ReLU 网络的属性,但也可以使用其他决策过程。我们的第二种技术使用决策树学习直接从数据中学习层属性的模式。学习到的模式可以使用决策程序进行最终检验。为了代替最终检验,我们可以在一个数据集上对学习到的结果进行实证验证,以验证其准确性。
我们认为这项工作是研究 DNNs 形式属性的第一步。作为一个概念的证明,我们提出了几个不同的应用。我们学习了 MNIST 网络的输入属性和层属性,并展示了它们在保证鲁棒性、解释网络的决策和调试网络的错误分类方面的用途。我们还研究了将中间层的模式作为插值器,用于证明给定的输入-输出属性的网络模型,即无人机控制的安全关键系统(ACAS XU)。这些学习到的模式有助于分解证明,从而使其在计算上更有效率。最后,我们讨论了一个略带争议的应用,即提炼 DNNs 的行为中学习到的模式。关键的想法是将可靠性高的模式作为提炼规则,直接决定网络的预测,而不需要评估整个网络。这样做的结果是在不损失太多精度的情况下大幅提高了速度。
如果一个隐藏层中的所有神经元都馈入下一层的所有神经元,那么一个前馈网络就被称为完全连接的网络;图 1 中的网络就是这样一个网络。卷积神经网络(Convolutional Neural Networks,CNNs)类似于 ReLU 网络,但除了全连接层之外,它们还可能包含卷积层,这些卷积层用不同的滤波器计算出输入的多个卷积,然后应用 ReLU 激活函数。为了简单起见,我们将讨论的重点放在 ReLU 网络上,但我们的工作适用于所有的片状线性网络,包括 ReLU 和 CNN。
我们的目标是提取网络行为的简洁的输入-输出特征,可以作为网络的正式规范。网络本身提供了一个输入-输出映射。理想的情况下,我们应该将导致相同输出的输入组合在一起,并以简洁的数学形式表达出来。输入属性是对输入空间的一个谓词,所有满足它的输入都会得到满足该属性 P 的输出。以一个分类网络的输出属性为例,假设理想的预测类别是 c,那么 P(Y)::=argmax(Y)=c。
在本文中,我们推断出输入属性,这些输入的特征是由网络以相同的方式处理的输入,也就是说,它们遵循相同的激活模式,并在输入空间中定义了凸区域。对于一个特定的输出属性(例如一个特定的预测),可能有许多这样的凸区域。在实际应用中,精确计算这些区域的联合代价较高,但我们最终证明了,即使是计算这些区域的子集也能满足许多场景下的应用。
我们进一步研究了层属性,在中间层编码共同的属性,这些属性预示着了所需的输出结果。神经网络的工作原理是通过在输入数据上采用若干个隐藏层,提取数据的重要特征,然后根据这些特征做出决策。因此,层属性可以潜在地捕捉到提取的特征上的共同特征,使我们能够洞察到网络的内在工作原理。与输入属性类似,我们试图通过研究网络的激活模式来推断层属性。与输入属性不同的是,层属性并不映射到输入空间中的凸区域,而是映射到凸输入区域的联合。
为了构建输入属性,我们对输入属性进行推测,这些输入属性是输入空间中的凸谓词,暗示着给定的后置条件。考虑到前馈 ReLU 网络编码属于高度非凸函数,输入属性的存在本身就值得研究。为了识别输入属性,我们考虑决策模式,其中对于模式中的每个神经元 N,所有馈入 N 的神经元也包括在该模式中。我们称这种模式为闭合。我们表明,闭合模式捕获了输入空间中的凸谓词。
虽然推断的输入属性可能很容易解释,但它们往往支持的范围很小。例如,一个基于输入 X 的激活特征定义的属性可能只被 X 和可能是语法上接近 X 的其他几个输入所满足。为此,我们将注意力集中在中间层的决策模式上,以捕捉高级特征。
注意,图层属性在该层的值空间中是凸的,但在输入空间中不是凸的。然而,将图层属性表示为输入前提条件的解结是较为容易的。这是通过将一个图层模式与所有可能的模式扩展到(直接或间接)馈入该图层的神经元上的所有可能的模式来实现的。每个这样的扩展模式都是闭合的,因此是凸的。
鲁棒性保证和对抗样本。我们为证明正确的输入属性和层属性定义了预测后置条件。在输入空间中,网络保证对相同标签对应相同的区域,此时网络是鲁棒性的。从模式候选者的反例中产生的输入,由于它们(在欧几里得空间中)接近于分类不同的输入(区域),因此代表了潜在的对抗样本。
解释网络的预测依据。神经网络因是复杂的黑箱而一直以来备受质疑。解释神经网络的一个重要难题是:理解为什么网络会对一个输入进行某种预测。我们对于预测属性的研究(确保预测是某一类的)可以用来获得这样的解释。但是,只有当这些属性本身是可以理解的时候,这些属性才是有用的解释。当输入空间是低维的时候,这样的区域很容易解释。
对于具有高维输入的网络(例如,图像分类网络),输入属性可能难以解释或可视化。这里的传统方法是通过给每个输入特征分配一个重要性权重(称为属性)来解释预测。归因法可以被可视化为一个热图叠加在输入的可视化上。在此基础之上,我们提出了两种不同的方法来从输入属性中获得类似的可视化。我们注意到,与归因法相比,我们提出的输入属性有助于解释单个输入的预测,而我们提出的输入属性有助于解释输入空间的区域预测。
现在我们介绍两种技术,从前馈网络中构建输入和层属性的前馈网络 wrt 凸输出属性 P。
这是一种提取输入属性的技术,它利用了一个现成的神经网络决策程序。在这项工作中,我们使用了 Reluplex,但也可以使用其他的决策程序。
上一节中描述的贪心算法的计算成本很高,因为它每一步都要调用一个决策过程。我们现在提出一种成交相对较低的技术,它依赖于数据,避免了多次调用决策过程。我们的想法是观察大量输入的激活特征,并学习各种输出属性的决策模式。在本文中,我们使用决策树学习来提取基于层中神经元的激活状态(激活或未激活状态)的紧凑规则。采用决策树是很有必要,因为决策树能够根据各种信息理论的衡量标准得到一个决策模式,并且是紧凑的(因此具有较高的可靠性)。所得到的模式是经过实证验证的层属性,可以通过对决策过程的一次调用来正式检验。
在本节中,我们讨论了计算输入属性和层属性的案例研究,并将其用于不同的应用。我们用 Python3.0 和 Tensorflow 实现了我们所有的算法。我们的 Python 笔记本连接到 Python2Google 计算引擎后端,并分配了 12Gb RAM。我们使用 Reluplex 来进行证明,它只限于 ReLU 网络。为了执行决策模式,我们修改了 Reluplex 来约束中间神经元值。随着更多的神经网络的决策程序变得可用,我们计划将其纳入我们的工具中,从而扩展其适用性。Reluplex 的运行是在 Ubuntu v16.04(8 核,64GB RAM)的服务器上完成的。我们使用线性编程求解器 pulp 2.3.1 来求解欠近似框。我们计划在最终版本中提供实现和网络。
我们首先讨论了 ACAS XU 的分析,ACAS XU 是无人驾驶飞机控制的安全关键型防撞系统。ACAS X 是美国联邦航空局(FAA)正在开发的飞机防撞系统家族。ACAS XU 是针对无人机的版本。作为对标无人机的版本,它接收无人机(机身)和附近任何入侵的无人机的传感器信息,然后发出水平转弯警告,以防止碰撞。输入的传感器数据包括:
(1)Range:自有船与入侵者之间的距离;
(2)θ:入侵者相对于自有船的航向角度;
(3)ψ:入侵者相对于自有船的航向角度;
(4)vown:自有船的速度;
(5)vint:入侵者的速度;
(6)τ:失去垂直分离的时间;
(7)aprev:以前的警告。
FAA 正在探索 ACAS XU 的一个实现,它使用了 45 个深度神经网络的阵列,我们在此选择了一个网络来讨论。五种可能的输出如下:
(0)Clear-of-Conflict(COC);
(1)Weak Left;
(2)Weak Right;
(3)Strong Left;
(4)Strong Right。
我们分析的网络由 6 个隐藏层组成,每层有 50 个 ReLU 激活节点。我们使用了 384221 个已知标签的输入,ACASXU 网络采用 Reluplex 进行了分析。
我们还基于大量的手写数字集合的数据集,对图像分类网络 MNIST 进行了分析。它有 60,000 个训练输入图像,每个图像的特征是 784 个属性和属于 10 个标签中的一个。我们首先分析了从 Reluplex 分布的简单网络(包含 10 层,每层 10 个 ReLU 节点)对于蒸馏(一种常见的模型压缩方法)实验,我们使用了一个更复杂的 MNIST 网络。
1)属性推理。我们使用迭代放宽法提取输入属性,使用决策树学习法提取层属性,最终证明了我们的方法在图像分类中的可行性。与 ACAS XU 相比,图像分类涉及的输入空间要大得多。
2)解释网络预测。我们进一步计算了推理属性的近似值域,并将其可视化。在图 2 中,我们展示了训练集中三个不同图像对应的输入属性的可视化。第一列显示的是原始图像。第 2 列和第 3 列分别显示了在计算出的欠逼近框中所有像素设置为最小值和最大值的图像。第 4 列、第 5 列和第 6 列分别将每个像素设置为框中的均值、随机选择的均值以下和随机选择的均值以上。
3)误分类。误分类的输入实例较少,并且分布在整个输入空间中,开发人员很难理解其原因,也很难修复其底层问题。
我们最后的实验是评估层属性在蒸馏网络中的使用。本文的核心想法是将中间层的预测属性作为蒸馏规则。对于满足该属性的输入,我们节省了从中间层开始评估网络的推理成本。我们用一个比较复杂的 MNIST 网络对这个想法进行了初步评估,该网络有 8 个隐藏层;两个卷积层、一个最大池化层、两个卷积层、一个最大池化层和两个全连接层。我们使用决策树算法获得层模式,然后对其进行实证验证(使用 5000 张图像的验证集),选出精度高于阈值 τ 的层。选择的属性被用作满足这些属性的输入的提炼规则。我们使用一个保留的测试数据集,测量不同值 τ 的混合设置的总体精度和推理时间。
图 3 显示了由 4608 个神经元组成的第一个最大池化层的蒸馏结果。X 轴显示的是用于选择属性的经验验证阈值。极右点(阈值>1)对应的是没有选择属性,因此没有触发蒸馏。图中显示了当阈值 τ 在 0.9 到 1.0 之间变化时,整体精度和推理时间的趋势。观察到,在阈值 τ=0.98 的情况下,推理时间可以节省 22%,而精度从 0.9943 下降到 0.9903,这是相当有希望的。正如预期的那样,降低阈值进一步考虑了更多的属性,从而减少了推理时间和精度。
本文提出了提取神经网络输入输出属性的技术,并讨论了它们在解释神经网络、保证神经网络鲁棒性、简化证明和提炼网络方面的应用。随着神经网络的决策程序越来越多,我们计划将其纳入我们的工具中,从而扩展其适用性和可扩展性。我们还计划利用这些决策模式来获得神经网络的并行验证技术,并研究推理属性的其他应用,如可靠性和安全攸关系统的信任建模、对抗性检测等。
本文由南京大学软件学院 2019 级硕士刘佳玮转述
来源:https://www.sitepoint.com/
现代应用相比普通的网页有不同的要求。但是浏览器是一个有着一套(大部分)固定可用的技术的平台,JavaScript依然是web应用的核心语言;任何需要在浏览器上跑的应用都需要使用这种语言。
我们都知道Javascript并不是最好的语言,特别是在复杂的应用中,它可能不太能胜任。为了避免这种情况,一些新的语言或现有语言的编译器被创造出来,你不用写一行Javascript或者考虑这种语言的局限,就能生产在浏览器能运行的代码。
这篇文章包括了十种有趣的语言能够编译为Javascript,在浏览器或者Node.js中被执行。
--ADVERTISEMENT--
Dart
Dart是一个典型的面向对象的语言,任何东西都是一个对象并且任何对象都是一个类的实例(对象也可以表现为函数)。它的特殊性用于打造面向浏览器,服务器和移动设备的应用。它由谷歌来维护,是用于驱动下一代的AdWords UI。AdWords UI是谷歌盈利的重要产品,这也证明了它在体量上的强大。
这种语言可以编译为JavaScript用于浏览器,或者直接通过Dart VM解释,这样也可以允许你构建服务端应用。移动应用可以通过Flutter SDK创建。
复杂的应用还需要一系列特别为任务所设计的成熟的库和语言特性,Dart这些都有。举例来说一个流行的库是AngularDart,一个Dart版本的Angular。
它允许你写非侵入式的类型安全的代码,但是这不是必须的,因为他们可以自动检测类型。它可以允许你快速构建原型而不用过于思考细节,一旦你需要的时候,你可以加入类型让它更健壮。
至于在VM中的并发编程,相比与共享内存线程(Dart是单线程的),Dart使用所谓的_Isolates_,有它自己的堆内存,而交流是通过传递信息。在浏览器上,情况就有点不一样了:相比与创建一个新的_isolates_,你创建一个新的_Workers_。
// Example extracted from dartlang.org
import 'dart:async';
import 'dart:math' show Random;
main() async {
print('Compute π using the Monte Carlo method.');
await for (var estimate in computePi()) {
print('π ? $estimate');
}
}
/// Generates a stream of increasingly accurate estimates of π.
Stream<double> computePi({int batch: 1000000}) async* {
var total=0;
var count=0;
while (true) {
var points=generateRandom().take(batch);
var inside=points.where((p)=> p.isInsideUnitCircle);
total +=batch;
count +=inside.length;
var ratio=count / total;
// Area of a circle is A=π?r2, therefore π=A/r2.
// So, when given random points with x ∈ <0,1>,
// y ∈ <0,1>, the ratio of those inside a unit circle
// should approach π / 4\. Therefore, the value of π
// should be:
yield ratio * 4;
}
}
Iterable<Point> generateRandom([int seed]) sync* {
final random=new Random(seed);
while (true) {
yield new Point(random.nextDouble(), random.nextDouble());
}
}
class Point {
final double x, y;
const Point(this.x, this.y);
bool get isInsideUnitCircle=> x * x + y * y <=1;
}
Get started with Dart https://www.dartlang.org/guides/get-started
TypeScript
TypeScript 是Javascript的超集;一个有效的Javascript项目也是一个有效的TypeScript项目只是添加了静态类型。编译器也可以作为ES2015+到当前实现的转译器,这样你总是能得到最新的特性。
不同于其他语言,TypeScript保持了Javascript完整的精神,只是此外添加了增加代码可靠性的功能。这些功能就是类型注释和其他类型相关的功能,得益于专业工具像是静态分析器和其他工具在重构过程的加入,这些功能使写Javascript更加有趣。并且,类型的加入改善了你的应用不同组件之间的接口。
类型诊断是支持性的,你不必从一开始就写所有的类型。你可以先快速的写代码,然后再加入类型来让代码更稳定。
TypeScript同样也支持高级类型,像是交叉类型,联合类型,类型别名,可辨识联合和类型保护。你可以在TypeScript Documentation网站的Advanced Types页面查看。
如果你使用React的话,通过添加React类型,JSX也是支持的。
class Person {
private name: string;
private age: number;
private salary: number;
constructor(name: string, age: number, salary: number) {
this.name=name;
this.age=age;
this.salary=salary;
}
toString(): string {
return `${this.name} (${this.age}) (${this.salary})`;
}
}
——
Elm
Elm是一个可以编译成JS,HTML和JS的纯函数式编程语言。你可以只通过Elm创建一个完整的网站,这使得它是一个对像React这样的Javascript框架的一个很好的代替。通过它创建的应用自动使用了虚拟DOM库,使得它很快。一个大的加分项是内建的结构让你忘记数据流而是关注于数据声明和逻辑。
在Elm中,所有函数都是纯粹的,这意味着他们总是对一个给予的输入返回一个相同的输出。T他们不能做其他任何事情,除非你指定。举例来说,获取一个远程的API你会创建一个_command_函数来通讯外部世界,和一个 subscriptions 函数监听回复。另一个纯粹的点是,值是不可变的,当你需要什么的时候,你创建一个新值而不是改变它。
ELm的接受可以是平缓的;可以使用_ports_来和Javascript或其他库沟通。虽然Elm还没有到达版本1,它已经用于复杂大型的应用了,这使得它对复杂应用是一个可行的解决方案。
ELm其中一个吸引人的功能是初学者友好的编译器,它生成帮助你修复你的代码的信息,而不是产生难以阅读的信息。如果你正在学习这门语言,编译器本身就是一个大的帮助。
module Main exposing (..)import Html exposing (..)-- MAINmain : Program Never Model Msgmain=Html.program { init=init , update=update , view=view , subscriptions=subscriptions }-- INITtype alias Model=Stringinit : ( Model, Cmd Msg )init=( "Hello World!", Cmd.none )-- UPDATEtype Msg=DoNothingupdate : Msg -> Model -> ( Model, Cmd Msg )update msg model=case msg of DoNothing -> ( model, Cmd.none )-- VIEWview : Model -> Html Msgview model=p [] [text model]-- SUBSCRIPTIONSsubscriptions : Model -> Sub Msgsubscriptions model=Sub.none
Get Started with Elm:https://www.sitepoint.com/functional-reactive-programming-elm-introduction/
PureScript
PureScript 是一个纯函数强类型的编程语言,由Phil Freeman创造。它旨在与现有的JavaScript库进行很好的兼容,与Haskell精神上类似,但是核心保留了Javascript。
PureScript一个重要的点是它的极简主义。它没有包含任何在其他语言认为很重要的功能库。比如,相比于在编译器中包含generators和promises,你可以自己使用指定的库来完成这个任务。你可以选择你想要的功能的实现,当使用PureScript的时候需要高效和个性化的经验,能使生成的代码尽可能的小。
这个编译器另一个重要的功能是构建出清晰可读的代码,能够兼容Javascript包括库和工具。
和其他语言一样,PureScript有它自己的构建工具称为Pulp,可以和Gulp做对比,只是用这个语言写的。
至于类型系统,不同于另一个ML类的语言Elm,PureScript支持更先进的类型特性比如高级类类型和类型类,这些是从Haskell来的特性,允许创建复杂的抽象。
module Main whereimport Preludeimport Data.Foldable (fold)import TryPureScriptmain=render $ fold [ h3 (text "Try PureScript!") , p (text "Try out the examples below, or create your own!") , h2 (text "Examples") , list (map fromExample examples) ] where fromExample { title, gist }=link ("?gist=" <> gist) (text title) examples=[ { title: "Algebraic Data Types" , gist: "37c3c97f47a43f20c548" } , { title: "Loops" , gist: "cfdabdcd085d4ac3dc46" } , { title: "Operators" , gist: "3044550f29a7c5d3d0d0" } ]
Get Started with PureScripthttps://github.com/purescript/documentation/blob/master/guides/Getting-Started.md
CoffeeScript
CoffeeScript是一个旨在暴露JavaScript的精华并提供一个干净的语法并在合适地方保留语义的语言。虽然近年来这个语言的热度在下降,它正在改变方向并且现在有一个新的大版本支持ES2015+特性。
你用CoffeeScript写的代码直接转化为可读的Javascript代码并且兼容现有的库。从2版本开始,编译器会产生兼容最新版本的ECMAScript的代码,比如,每次你使用class,你就在Javascript中得到class。并且,如果你使用React,好消息是,JSX兼容CoffeeScript。
这个编译器有一个十分有特色的功能是有能力处理用literate style写的代码。literate style相比于强调代码而把注释作为添加这种方式,而是你需要在一开始就写注释,代码只是偶尔出现。这种写代码的方式由Donald Knuth推荐,使得一个代码文件非常像一个技术文档。
相比于其他语言,CoffeeScript代码可以在浏览器中用一个库直接执行。所以如果你想要写一个快速测试,你可以写你的代码在一个text/coffeescriptscript标签中,并且引入编译器,这样就可以把你的代码轻易的转化为JavaScript了。
# Assignment:number=42opposite=true# Conditions:number=-42 if opposite# Functions:square=(x) -> x * x# Arrays:list=[1, 2, 3, 4, 5]# Objects:math=root: Math.sqrt square: square cube: (x) -> x * square x# Splats:race=(winner, runners...) -> print winner, runners# Existence:alert "I knew it!" if elvis?# Array comprehensions:cubes=(math.cube num for num in list)
Get Started with CoffeeScript http://coffeescript.org/v2/#coffeescript-2
ClojureScript
ClojureScript是一个转化Clojure编程语言为JavaScript的编译器。Clojure是一个多用途的函数式原因伴随着动态类型和不可变数据结构的支持。
这是这个列表中唯一一个属于Lisp家族的语言,自然有着它们共同的特性。举例来说,代码可以作为数据,支持宏系统,使得元编程成为可能。Unlike other Lisps, Clojure has support for immutable data structures, making the management of side-effects easier.不同于其他类Lisp,Clojure支持不可变数据结构,使得函数副作用的管理更容易。
这个语法对初学者看起吓人,因为圆括号的使用。但这样使用是经过深思熟虑的,并且在长远看来你一定会感谢这种语法的。语法的极简和抽象能力使得Lisp成为一个解决高抽象问题的强力工具。
虽然Clojure主要是一个函数式语言,但是不像PureScript或者Elm那样纯粹。函数副作用还是会发生,但是其他函数式特性也会存在。
ClojureScript使用Google Closure做代码优化并且也兼容现有的JavaScript库。
; Extracted from https://github.com/clojure/clojurescript/blob/master/samples/dom/src/dom/test.cljs(ns dom.test (:require [clojure.browser.event :as event] [clojure.browser.dom :as dom]))(defn log [& args] (.log js/console (apply pr-str args)))(defn log-obj [obj] (.log js/console obj))(defn log-listener-count [] (log "listener count: " (event/total-listener-count)))(def source (dom/get-element "source"))(def destination (dom/get-element "destination"))(dom/append source (dom/element "Testing me ") (dom/element "out!"))(def success-count (atom 0))(log-listener-count)(event/listen source :click (fn [e] (let [i (swap! success-count inc) e (dom/element :li {:id "testing" :class "test me out please"} "It worked!")] (log-obj e) (log i) (dom/append destination e))))(log-obj (dom/element "Text node"))(log-obj (dom/element :li))(log-obj (dom/element :li {:class "foo"}))(log-obj (dom/element :li {:class "bar"} "text node"))(log-obj (dom/element [:ul [:li :li :li]]))(log-obj (dom/element :ul [:li :li :li]))(log-obj (dom/element :li {} [:ul {} [:li :li :li]]))(log-obj (dom/element [:li {:class "baz"} [:li {:class "quux"}]]))(log-obj source)(log-listener-count)
Get Started with ClojureScript https://clojurescript.org/guides/quick-start
Scala.js
Scala.js是一个将Scala编程语言转化为JavaScript的编译器。Scala是一个旨在融合面向对象和函数式编程两种思想到一种语言,为了打造容易接受的强力的工具
作为一个强类型语言,你会从它部分类型推断这种灵活的类型系统中受益。大部分的值会被推断,但函数参数仍然需要明确的类型注释。
虽然许多通常的面向对象模式都支持(比如任何值都是一个对象并且操作是一个方法调用),但你也有函数式特性比如一等函数和不可变数据结构。
Scala.js其中一个特殊的优势是,你可以毫不费力的从你熟悉的面向对象开始向更函数式的转移,以你自己的需要和步调。同样的,现存的JavaScript代码和库和你的Scala代码兼容。
Scala的初学者会发现这个语言和JavaScript并没有多大不同,对比下面两个意思一样的代码:
// JavaScript
var xhr=new XMLHttpRequest();
xhr.open("GET",
"https://api.twitter.com/1.1/search/" +
"tweets.json?q=%23scalajs"
);
xhr.onload=(e)=> {
if (xhr.status===200) {
var r=JSON.parse(xhr.responseText);
$("#tweets").html(parseTweets(r));
}
};
xhr.send();
// Scala.js
val xhr=new XMLHttpRequest()
xhr.open("GET",
"https://api.twitter.com/1.1/search/" +
"tweets.json?q=%23scalajs"
)
xhr.onload={ (e: Event)=>
if (xhr.status==200) {
val r=JSON.parse(xhr.responseText)
$("#tweets").html(parseTweets(r))
}
}
xhr.send()
Get Started with Scala.jshttps://www.scala-js.org/tutorial/basic/
Reason
Reason是一个由Facebook创造和维护的语言,它为OCaml编译器提供了新的语法,并且代码可以转换成JavaScript和原生代码。
作为ML家族的一部分并且自己本身是函数式语言,它天生提供了强大但是灵活的伴随类型推断的类型系统,代数数据类型和模式匹配。它也支持不可变数据类型和参数多态(也被其他语言称为泛型),但是在OCaml中,也是支持面向对象编程的。
通过 bucklescript绑定就可以使用现存的JavaScript库。你也可以在你的Reason代码旁边混入你的JavaScript。插入的JavaScript代码不会严格的检查,但作为快速修复和原因也是不错的。
如果你是一个React开发者,绑定是可能的,并且这个语言也支持JSX。
/* A type variant being pattern matched */let possiblyNullValue1=None;let possiblyNullValue2=Some "Hello@";switch possiblyNullValue2 {| None=> print_endline "Nothing to see here."| Some message=> print_endline message};/* Parametrized types */type universityStudent={gpa: float};type response 'studentType={status: int, student: 'studentType};let result: response universityStudent=fetchDataFromServer ();/* A simple typed object */type payload=Js.t {. name: string, age: int};let obj1: payload={"name": "John", "age": 30};
Get Started with Reason https://reasonml.github.io/guide/javascript/quickstart
Haxe
Haxe是一个多范式编程语言,并且它的编译器可以产生二进制或者其他语言的源代码。
虽然Haxe提供了严格的类型系统并带有类型推断,它也可以作为动态语言只要目标语言支持。同样的,它也支持多种的编程风格比如面向对象,泛型,函数式。
当你写Haxe代码的时候,你可以为编译指定多个平台或语言,但不需要对代码做什么大的改变。指定目标的代码块也支持。
你可以用Haxe同时写前端和后端用同样的代码,并且通过Haxe Remoting进行沟通,既可以同步连接也可以异步连接。
不出所料,Haxe代码可以兼容现有的库但也提供了成熟的标准库。
// Example extracted from http://code.haxe.org
extern class Database {
function new();
function getProperty<T>(property:Property<T>):T;
function setProperty<T>(property:Property<T>, value:T):Void;
}
abstract Property<T>(String) {
public inline function new(name) {
this=name;
}
}
class Main {
static inline var PLAYER_NAME=new Property<String>("playerName");
static inline var PLAYER_LEVEL=new Property<Int>("playerLevel");
static function main() {
var db=new Database();
var playerName=db.getProperty(PLAYER_NAME);
trace(playerName.toUpperCase());
db.setProperty(PLAYER_LEVEL, 1);
}
}
Get Started with Reasonhttps://haxe.org/documentation/introduction/language-introduction.html
Nim
Nim是一个静态类型,多范式编程语言,有着极简风格与空格敏感的语法,编译为C,C++和JavaScript。
这个语言本身很小,但它的元编程能力会吸引你自己去实现一些在别的语言内置的功能。这些构建模块有宏,模板和泛型,通过它们你可以实现不论是简单的功能还是不同的泛型。这使得Nim成为一个非常通用的语言可以适应你的需求,有着Lisp的精髓。
Nim的语法抽象功能允许你去让语言去适应你的功能,让真正的[DSLs][20]成为可能。如果你有着专门的任务需要处理,你可以获得更高级的表达性。
# Reverse a stringproc reverse(s: string): string=result="" for i in countdown(high(s), 0): result.add s[i]var str1="Reverse This!"echo "Reversed: ", reverse(str1)# Using templatestemplate genType(name, fieldname: expr, fieldtype: typedesc)=type name=object fieldname: fieldtypegenType(Test, foo, int)var x=Test(foo: 4566)echo(x.foo) # 4566
Get Started with Nimhttps://nim-lang.org/documentation.html
结尾
如果JavaScript不是你最喜欢的语言,你依然可以创建web应用而不用忍受这个技术的缺点。可供选择的范围很广,从纯粹的函数式语言,比如PureScript,到面向对象语言,比如Dart。并且如果你想要不只是语言的转化,你也可以选择比如Elm,Elm提供像是虚拟DOM和内置的架构这样的工具。
你是否有尝试了这篇文章的任何一种语言,又或者你有自己的推荐?请在评论中让我知道!
有很多令人信服的理由来用 Pulp 来托管你自己的容器注册中心。下面是其中的一些。
Linux 容器极大地简化了软件发布。将一个应用程序与它运行所需的一切打包的能力有助于提高环境的稳定性和可重复性。
虽然有许多公共注册中心可以上传、管理和分发容器镜像,但有许多令人信服的论据支持托管自己的容器注册中心。让我们来看看为什么自我托管是有意义的,以及 Pulp,一个自由开源项目,如何帮助你在企业内部环境中管理和分发容器。
你可以考虑托管自己的容器注册中心,原因有很多:
体积:一些容器镜像是相当大的。如果你有多个团队下载同一个镜像,这可能需要大量的时间,并给你的网络和预算带来压力。带宽:如果你在一个带宽有限的地区工作,或在一个出于安全原因限制访问互联网的组织中工作,你需要一个可靠的方法来管理你工作的容器。金钱:服务条款可以改变。外部容器注册中心能引入或增加速率限制阈值,这可能会对你的操作造成极大的限制。稳定性:托管在外部资源上的容器镜像可能会因为一些原因消失几天。小到你所依赖的更新容器镜像,可能会导致你想要避免的重大更改。隐私:你可能也想开发和分发容器,但你不想在公共的第三方注册中心托管。使用 Pulp,你可以避免这些问题并完全控制你的容器。
在 Pulp 中创建容器镜像的本地缓存,可以让你组织中的每个人都能拉取到 Pulp 上托管的容器镜像,而不是从外部注册中心拉取。这意味着你可以避免速率限制,只有当你需要新的东西时才从外部注册中心进行同步。当你确实需要从外部注册中心同步容器时,Pulp 首先检查内容是否已经存在,然后再从远程注册中心启动同步。如果你受到注册中心的速率限制,你就只镜像你需要的内容,然后用 Pulp 在整个组织中分发它。
使用 Pulp,你可以创建一个仓库,然后从任何与 Docker Registry HTTP API V2 兼容的注册中心镜像和同步容器。这包括 Docker、Google Container registry、Quay.io等,也包括另一个 Pulp 服务器。对于你结合来自不同注册中心的镜像容器的方式,没有任何限制或约束。你可以自由地混合来自不同来源的容器。这允许你整理一套公共和私人容器,以满足你的确切要求。
在 Pulp 中,每当你对仓库进行修改时,就会创建一个新的不可变的版本。你可以创建多个版本的仓库,例如,development、test、stage 和 production,并在它们之间推送容器。你可以自由地将容器镜像的最新更新从外部注册中心同步到 Pulp,然后让最新的变化在开发或其他环境中可用。你可以对你认为必要的仓库进行任何修改,并促进容器内容被测试团队或其他环境使用。如果出了问题,你可以回滚到早期版本。
如果你想使用 Pulp 来创建一个容器子集的本地缓存,而不是一个完整的容器注册中心,你可以从一个远程源过滤选择容器。使用 Pulp,有多种内容同步选项,以便你只存储你需要的内容,或配置你的部署,按需缓存内容。
如果你在一个断线或受限制的环境中工作,你可以从一个连接的 Pulp 实例中同步更新到你断连的 Pulp。目前,有计划为 Pulp 实现一个原生的空气隔离功能,以促进完全断线的工作流程。同时,作为一种变通方法,你可以使用 Skopeo等工具来下载你需要的容器镜像,然后将它们推送到你断线的 Pulp 容器注册中心。
通过 Pulp,你还可以从容器文件中构建容器,将私有容器推送到仓库,并在整个组织中分发这些容器。我们将在未来的文章中对这个工作流程进行介绍。
如果你对自我托管你的容器注册中心感兴趣,你现在就可以 安装 Pulp。随着 Pulp Ansible 安装程序的加入,安装过程已经被大量自动化和简化了。
Pulp 有一个基于插件的架构。当你安装 Pulp 时,选择容器插件和其他任何你想管理的内容插件类型。如果你想测试一下 Pulp,你今天就可以评估 Pulp 的容器化版本。
如果你有任何问题或意见,请随时在 Freenode IRC 的 #pulp 频道与我们联系,我们也很乐意在我们的邮件列表 pulp-list@redhat.com中接受问题。
via: https://opensource.com/article/21/5/container-management-pulp
作者:Melanie Corr选题:lujun9972译者:geekpi校对:wxy
本文由 LCTT原创编译,Linux中国荣誉推出
发表评论