Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >改变开发者编码思维的六种编程范式

改变开发者编码思维的六种编程范式

作者头像
CSDN技术头条
发布于 2018-02-12 09:29:25
发布于 2018-02-12 09:29:25
2.3K0
举报
文章被收录于专栏:CSDN技术头条CSDN技术头条

译者注:本文介绍了六种编程范式,提到了不少小众语言,作者希望借此让大家更多的了解一些非主流的编程范式,进而改变对编程的看法。以下为译文:

时不时地,我会发现一些编程语言所做的一些与众不同的事情,也因此改变了我对编码的看法。在本文,我将把这些发现分享给大家。

这不是“函数式编程将改变世界”的那种陈词滥调的博客文章,这篇文章列举的内容更加深奥。我敢打赌大部分读者都没有听说过下面这些语言和范式,所以我希望大家能像我当初一样,带着兴趣去学习这些新概念,并从中找到乐趣。

注:对于下面讲到的大多数语言,我拥有的经验其实很少:我只是觉得他们背后的思想很赞,但对于它们没有任何相关的专业知识,所以有任何更正和错误请指出。此外,如果你发现任何没有包括在这里的新的范式和想法,请分享它们!

更新:这篇文章上了r/programming和HN首页,感谢反馈,我将会进行更正。

默认支持并发(Concurrent by default)

示例语言:ANI, Plaid

让我们先从改变思维开始:有一些编程语言是默认支持并发的。也就是说,每一行代码都是并行执行的!

例如,假设你写了三行代码,A,B和C:

A; B; C;

在大多数编程语言中,A将首先执行,接着B执行,最后C执行。在像ANI这样的编程语言中,A, B和 C将同时执行。

在ANI中代码行之间的控制流或者顺序只是代码行之间显式依赖的副作用。例如,如果B对A中定义的变量有引用,那么A和C将同时执行,而B将在A完成后执行。

来看一个ANI的例子。正如教程中所描述的,ANI 程序由用于操作流和数据流的“管道”和“锁存器”组成。这种非同一般的语法很难解析,ANI这门语言似乎已经死了,但概念还是相当有趣的。

下面是ANI中的“Hello World”示例:

代码语言:js
AI代码解释
复制
"Hello, World!" ->std.out

在ANI语法中,我们将“Hello World!”对象(一个字符串)发送到std.out流。如果我们发送另外一个字符串到std.out会怎样?

代码语言:js
AI代码解释
复制
"Hello, World!" ->std.out  
"Goodbye, World!" ->std.out

这两行代码并发执行,所以它们可能以任意顺序在控制台输出。现在,看看当我们在一行中引入一个变量并在之后引用会发生什么:

代码语言:js
AI代码解释
复制
s = [string\];  
"Hello, World!" ->s;  
\s ->std.out;

第一行声明一个叫做s的“锁存器”(锁存器有点像变量),其中包含一个字符串;第二行发送文本“Hello World!”发送到s;第三行“解锁”s并将内容发送到std.out。因此,你可以看到ANI的隐式程序排序:因为每一行运行都依赖于上一行,因此,这段代码将按照它编写的顺序执行。

Plaid语言也声称默认情况下支持并发,但使用的是本篇论文中所描述的一种权限模型来构建控制流。 Plaid还探讨了其它有趣的概念,如面向类型状态的编程,在那里状态转换成为了语言中的重要因素:你定义的对象不再是类,而是一系列可以由编译器检查的状态和转换。看起来十分有趣,正如Rich Hickey在演讲“Are we there yet”中所讨论的,将时间作为语言结构的首要因素。

Multicore正处在上升期,并发性仍然比大多数语言更难。ANI 和 Plaid 对于这个可能产生惊人的性能提升的问题提供了一个新的思路;不过问题是“默认支持并行”是否让并发更容易或难以管理。

更新:上面的描述讲解了ANI和Plaid的基本本质,但我可互换地使用术语“并发”和“并行”,即使它们有不同的含义。如果想了解更多信息请阅读“并发不是并行”这篇文章。

依赖类型 (Dependent types)

示例语言:Idris, Agda, Coq

你可能习惯于像C和JAVA等语言的类型系统,编译器可以检查一个变量是整数,列表,或者字符串。但是如果你的编译器可以检查一个变量是“正整数”,“长度为2的列表”,还是“一个回文字符串”会怎样呢?

这就是支持依赖类型语言背后的思想:你可以在编译时指定检查变量值得类型。Scala的Shapeless库添加了对Scala依赖类型的部分实验性质支持,并提供了观察一些例子的简单方法。

下面是如何声明一个Vector的代,其中使用了shapeless库,包含值1、2、3:

代码语言:js
AI代码解释
复制
val l1 = 1 :#: 2 :#: 3 :#: VNil

这里创建了一个变量l1,它的类型签名不仅指定它是一个包含Ints的Vector,还指定了它的长度是3。编译器可以使用这个信息来捕获错误。让我们使用Vector中的vAdd方法来执行两个Vector间的成对相加(pairwise addition):

代码语言:js
AI代码解释
复制
val l1 = 1 :#: 2 :#: 3 :#: VNil  
val l2 = 1 :#: 2 :#: 3 :#: VNil


val l3 = l1 vAdd l2


// Result: l3 = 2 :#: 4 :#: 6 :#: VNil

上面的例子运行正常,因为类型系统知道两个Vector的长度都是3.。然而,如果我们尝试两个长度不同的Vectors,我们会在编译时得到一个错误。

代码语言:js
AI代码解释
复制
val l1 = 1 :#: 2 :#: 3 :#: VNil
val l2 = 1 :#: 2 :#: VNil


val l3 = l1 vAdd l2


// Result: a *compile* error because you can't pairwise add vectors 
// of different lengths!

Shapeless是一个了不起的库,但在我看来,它仍然有点粗糙,只支持依赖类型的一个子集,并导致生成相当详细的代码和类型签名。另一方面,Irdris,使类型成为编程语言的首要成员,所以,依赖类型系统似乎更强大和更干净。为了比较,可以看看“Scala VS Idris:从属依赖类型的,在现在和未来”演讲。

形式化验证方法已经存在很长一段时间了,但往往过于繁琐,不适用于通用编程。依赖类型的语言,如Idris,甚至在未来的Scala中,可能会提供更轻量级和更实用的替代方案,这仍然可以显著的提高类型系统捕捉错误的能力。当然,由于终止问题的固有限制,没有哪个依赖类型系统可以捕捉到全部错误,但如果做得好,依赖类型可能是静态类型系统下一个大的飞跃。

拼接语言(Concatenative languages)

示例语言:Forth, cat ,joy

想象过,在没有变量和函数应用的情况下,编写程序是什么样子的吗?没有?我也没试过。但显然有人做了,他们提出了拼接编程。这个概念背后的思想是语言中的都是把数据压入堆栈或者弹出堆栈的函数;程序几乎完全通过功能组合来构建(基于堆栈的编程语言)。

这听起来相当抽象,所以让我们来看cat语言中一个简单的例子:

代码语言:js
AI代码解释
复制
2 3 +

在这里,我们将两个数字推倒堆栈上,然后调用+函数,它将两个数字从堆栈中弹出,并将它们相加的结果添加到堆栈:代码的输出是5。下面是一个更有趣一点的例子:

代码语言:js
AI代码解释
复制
def foo {
  10 <
  [ 0 ]
  [ 42 ]
  if
}


20
foo

让我们逐行解读上面的代码:

  • 首先,我们声明一个函数foo。注意,在CAT中函数不指定输入参数:所有参数都是从堆栈中隐式读取的。
  • foo调用<函数,它从堆栈上弹出堆栈的第一个选项,将其与10进行比较,并将true或false返回到堆栈。
  • 接下来,我们将0和42推到堆栈:我们把它们放在括号中以确保它们推到未被评估堆栈上。这是因为这是因为它们将被用作“then”和“else”分支(分别)用于调用下一行的 if 函数。
  • if函数在堆栈中弹出3个选项:布尔条件、“then”和“else”分支。根据布尔条件的值,它将会把“then”或“else”分支的结果推回到堆栈。
  • 最后,我们将20推到堆栈并调用函数foo。
  • 当上面所说流程都完成后,我们将最终得到数字42.

更详细的介绍,请参看“ The Joy of Concatenative Languages ” :http://www.codecommit.com/blog/cat/the-joy-of-concatenative-languages-part-1

这种编程风格有一些有趣的属性:

  • 程序可以通过无数种方式分割和连接以创建新的程序;
  • 极简的语法(甚至比 LISP 还小)产生了非常简洁的程序;
  • 强大的元编程支持

我发现拼接编程是一个令人大开眼界的思想实验,但我还未实践过。似乎你必须记住或想象堆栈的当前状态,而不能够从代码中的变量名读取它,这会使代码很难理解。

声明式编程(Declarative programming)

示例语言:Prolog, SQL

声明式编程已经存在了许多年,但大多数程序员仍然不知道它是怎样的概念。简单来说:在大多数主流语言中,开发者是在描述如何解决一个特定的问题;在声明式语言中,你只需要描述你想要的结果,而语言本身确定如何到达那里。

例如,如果你使用C语言从头开始写一个排序算法,你可能会为合并排序写一个说明,一步一步的描述如何递归地将数据集分割成两部分并将其合并到一起:这里是一个例子。如果使用声明式语言如Prolog来进行数字排序,可直接描述你想要的输出:“我想要相同的值列表,但每个索引i中的每个项目都应小于或等于索引为i+ 1的项”。将前面的C语言解决方案和下面的Prolog代码进行对比:

代码语言:js
AI代码解释
复制
sort_list(Input, Output) :-
  permutation(Input, Output),
  check_order(Output).


check_order([]).
check_order([Head]).
check_order([First, Second | Tail]) :-
  First =< Second,
  check_order([Second | Tail]).

如果你使用过SQL,那么你已经使用了声明式编程,可能自己没有意识到这一点:当你发出一个像 select X from Y where Z 这样的查询,你就是在描述你想要返回的数据集;数据库引擎的工作实际上是如何执行查询。你可以在大多数数据库中使用 explain 命令来查看执行计划并弄清楚在引擎下发生了什么。

声明式语言之美在于它们允许你在更高层次的抽象下工作:你的工作就是描述你想要的输出规格。例如,在Prolog语言中一个简单的数独求解器的代码只需要列出每行,每列,和一个解决的数独难题的对角线应该看起来的样子:

代码语言:js
AI代码解释
复制
sudoku(Puzzle, Solution) :- 
Solution = Puzzle,


  Puzzle = [S11, S12, S13, S14,
S21, S22, S23, S24,
S31, S32, S33, S34,
S41, S42, S43, S44],


  fd_domain(Solution, 1, 4),


  Row1 = [S11, S12, S13, S14],
  Row2 = [S21, S22, S23, S24],
  Row3 = [S31, S32, S33, S34],
  Row4 = [S41, S42, S43, S44],  


  Col1 = [S11, S21, S31, S41],
  Col2 = [S12, S22, S32, S42],
  Col3 = [S13, S23, S33, S43],
  Col4 = [S14, S24, S34, S44],  


  Square1 = [S11, S12, S21, S22],
  Square2 = [S13, S14, S23, S24],
  Square3 = [S31, S32, S41, S42],
  Square4 = [S33, S34, S43, S44],  


  valid([Row1, Row2, Row3, Row4,
 Col1, Col2, Col3, Col4,
 Square1, Square2, Square3, Square4]).


valid([]).
valid([Head | Tail]) :- fd_all_different(Head), valid(Tail).

下面是如何运行上面的数独求解器:

代码语言:js
AI代码解释
复制
| ?- sudoku([_, _, 2, 3,
 _, _, _, _,
 _, _, _, _,
 3, 4, _, _],
 Solution).




S = [4,1,2,3,2,3,4,1,1,2,3,4,3,4,1,2]

不幸的是,声明式编程语言的性能开销比较大。上面的单纯排序算法的复杂度接近O(n!);数独求解器使用暴力搜索;而且大多数开发人员不得不提供数据库提示和额外索引,以避免执行SQL查询时的昂贵和低效的计划。

符号式编程(Symbolic programming)

示例语言:Aurora

Aurora语言是符号式编程的一个例子:使用符号编程语言编写的“代码”不仅包括纯文本,还包括图像、数学方程、图、图表等。这允许你以数据的原生格式来操作和描述大量的数据,而不是完全用文本来描述它。Aurora是完全交互式的,它会立即显示每行代码的结果,像steroids中的REPL。

Aurora语言是由Chris Granger创造的,他还创建了Light Table IDE。克里斯在他的文章《为了更好地编程》中描述了创建Aurora的动机,目标是使编程更直观,直接,减少偶然的复杂性。欲了解更多信息,请参见Bret Victor的演讲:Inventing on Principle, Media for Thinking the Unthinkable, and Learnable Programming。

更新:“符号编程”可能不是适用于Aurora。更多信息参见维基百科上的“符号编程”的维基主页。

基于知识的编程(Knowledge-based programming)

示例语言:Wolfram语言

与上面提到的Aurora语言很像,Wolfram语言也是基于符号编程的。然而,符号层仅仅是提供一种与Wolfram语言核心一致的接口,Wolfram语言是基于知识的编程语言:内置了大量的库、算法和数据。这使得可以轻松地从图形化的Facebook连接,到处理图像,查找天气,处理自然语言查询,绘制地图上的方向,解决数学方程等等。

我猜想Wolfram语言拥有现存语言中最大的“标准库”和任何现有语言的数据集。我被“互联网连接(Internet connectivity)是代码编写的固有部分”这个想法所打动:它就像一个通过谷歌搜索来实现自动完成功能的集成开发IDE。这将是非常有趣的,看看符号编程模型是否像Wolfram声称的那样灵活,可以真正利用所有这些数据。

更新:虽然Wolfram声称Wolfram语言支持“符号式编程”和“知识编程”,但这些术语的定义是有所不同的。更多信息请参阅 Knowledge level 和 Symbolic Programming 的维基主页。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CSDN技术头条 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
java MD5 和 jsMD5 加密javajs引用
java private static final String SALT = "jzd,.,."; public static String encode(String password
用户5899361
2020/12/07
6600
VB实现的16位和32位md5加密代码分享
Private Function LShift(lValue, iShiftBits)
大师级码师
2022/11/06
6280
小程序进行md5加密无漏洞bug版
今天在进行小程序与后台接口进行加密验证时候,发现了个很奇妙的问题,一模一样的字符串,经后台(php)md5加密后打印出的结果和在小程序前端md5后的结果不一样,刚开始我以为是我传的参数有问题,多次检查没错,然后我尝试着用其他在线md5试了一下,发现结果和后台加密结果一模一样,很明显,小程序端加密出问题了。
许坏
2019/08/20
1.2K0
java之MD5
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/156895.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/08
3760
C/C++ 递归遍历文件并计算MD5
首先,需要引用 md5 的相关代码,参考这篇文章,防止链接内容被删除,这里再记录一次: md5.h
王 瑞
2022/12/28
1.1K0
MD5 算法的Java Bean
/**  * MD5 算法的Java Bean  * MD5 类实现了RSA Data Security, Inc.在提交给IETF 的RFC1321中的MD5 message-digest 算法。  */ public class MD5 {     //下面这些S11-S44实际上是一个4*4的矩阵,在原始的C实现中是用#define 实现的,这里把它们实现成为static final是表示了只读,切能在同一个进程空间内的多个Instance间共享     static final int S11 = 7;     static final int S12 = 12;     static final int S13 = 17;     static final int S14 = 22;
阿敏总司令
2019/02/28
6900
C#笔记:MD5加密类
MD5似乎要淘汰。现在推荐使用SHA256算法来进行替代。 但是我是一个非常念旧的人。我就是要使用MD5来加密。找了很久。终于让我找到了手工实现的类库。激动。。。。 实测可用。。
超级大猪
2019/11/21
8810
S参数通俗讲义
介绍信号完整性就必须说说S参数,在我们仿真和测试中经常会用的S参数,S参数的全称为Scatter 参数,即散射参数,是在传输线两端有终端的条件下定义出来的,一般是50Ω。我们把传输通道作为一个黑盒子看待,S参数描述的是这个黑盒子本身的频域特性。通过S参数,我们能看到传输通道的几乎全部特性,例如信号的反射,串扰,损耗,都可以从S参数中找到有用的信息,我们以反射为例了解下S参数。
工程师看海
2022/06/23
1.5K0
S参数通俗讲义
计算md5的C++代码(与java结果相同)
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/52383961
10km
2019/05/25
3.8K0
(win环境)使用Electron打造一个桌面应用翻译小工具
因为之前我们在package.json已经编辑过了devDependencies,所以我们直接。
Vam的金豆之路
2021/12/01
5590
(win环境)使用Electron打造一个桌面应用翻译小工具
哈希长度扩展攻击
0x00 简介 Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来唯一的确定输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。 –摘自百度 哈希长度扩展攻击简单的来讲就是: 1.知道一个密文(SECRET)的哈希 2.知道密文的长度(SEC
WeaponX
2018/05/04
2.1K0
哈希长度扩展攻击
ArkUI实战开发-引入三方库
笔者在第 4 小节里基于前 3 小结的知识点简单扩展了一个 md5() 方法并成功在 JS 代码里调起了 C++ 代码,本节笔者简单介绍一下引入三方库编译的知识点。
小帅聊鸿蒙
2024/10/10
1370
ArkUI实战开发-引入三方库
C++:符合RFC1321规范的MD5计算C++实现
MD5使用比较广泛,并不只局限于数据加密,它的概念这里就不介绍了,这里只谈谈MD5的代码实现。 MD5计算的算法是统一的,但实现如果实现时参数不一样,同样一段数据,不同的算法计算出的结果就不一样。为了保证MD5算法实现在不同的平台,不同的语言实现时计算结果一致,人们制定了RFC1321规范。比如java中MD5的算法实现就是遵循RFC1321规范的。我们知道C/C++并没有内置MD5计算的函数,所以在C++/C环境下要实现与java平台一样的MD5计算,就要自己实现。 RFC1321的官方网站提供了MD5的C语言实现。这是很权威的了。 但如果想要C++的版本,就要仔细挑选了。我们当然希望自己的MD5实现计算出来的结果与别的系统计算的结果一样,所以遵循RFC1321是必须的。网上也可以找到很多C++版本的实现。但哪一个遵循RFC1321规范的呢? 最近我就遇到了这个问题,经过实际测试,可以确认下面这个版本是没问题的,遵循RFC1321,与java平台下计算的结果一致。 http://www.zedwood.com/article/cpp-md5-function
10km
2019/05/25
4K0
js的常见的三种密码加密方式-MD5加密、Base64加密和解密和sha1加密详解总结
写前端的时候,很多的时候是避免不了注册这一关的,但是一般的注册是没有任何的难度的,无非就是一些简单的获取用户输入的数据,然后进行简单的校验以后调用接口,将数据发送到后端,完成一个简单的注册的流程,那么一般来说,密码是不做加密的。但是也有一些数据库里面存放的是加密后的密码,这样有一个比较安全的地方在于,即使黑客将用户输入的文本密码得到了,也不知道具体是什么,因为密码是经过加密的。
何处锦绣不灰堆
2020/05/29
16.1K0
js的常见的三种密码加密方式-MD5加密、Base64加密和解密和sha1加密详解总结
MD5加密详解_md5加密的方法
  Message Digest Algorithm MD5(中文名为信息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。
全栈程序员站长
2022/09/20
6.5K0
MD5的介绍,算法和C、VB、Delphi实现
http://download.winzheng.com/infoView/Article_861.htm
阿敏总司令
2019/02/28
9520
asp中的md5/sha1/sha256算法收集
对于asp这种古董级的技术,这年头想找一些有用的资料已经不容易了,下面是一些常用的加密算法: md5 (将以下代码另存为md5.inc) <% Private Const BITS_TO_A_BYTE = 8 Private Const BYTES_TO_A_WORD = 4 Private Const BITS_TO_A_WORD = 32 Private m_lOnBits(30) Private m_l2Power(30) Private Function LShift(lValue, iShif
菩提树下的杨过
2018/01/19
1.4K0
6 个新奇的编程方式,改变你对编码的认知
源 | Reddit 译 | OSC - 周其 我时不时会发现一种编程语言的不同用法它有时候会改变我对编程的看法啊。这篇文章中,我想分享一下让我惊讶的发现。这不是类似于高呼“函数式编程会改变世界!”博客文章。我敢打赌,大多数读者都没有听说过下面的大多数语言和范例,所以你应该也会被这些新概念吸引。 注意:我对以下大多数语言的使用经验都很少,但是我发现他们背后的想法非常吸引人,但对其没有专业知识,所以有任何错误请指出并指导更正。如果您也有新的范例和想法,欢迎分享。 默认并发 示例语言:ANI,
顶级程序员
2018/04/26
2.5K0
6 个新奇的编程方式,改变你对编码的认知
【机组】基于FPGA的32位算术逻辑运算单元的设计(EP2C5扩充选配类)
1、完成32位不带进位位算术、逻辑运算实验。按照实验步骤完成实验项目,了解算术逻辑运算单元的运行过程。
SarPro
2024/02/20
2530
【机组】基于FPGA的32位算术逻辑运算单元的设计(EP2C5扩充选配类)
圣诞树代码 下雪
圣诞树代码--下雪 实例如下: 站长源码网 <!DOCTYPE html> <html lang="en">   <head>     <meta charset="UTF-8" />     <title>Minimalistic Winter Snowfall</title>     <style>       body {         background: #134;         margin: 0 auto;         box-shadow: none;       }     
很酷的站长
2023/01/08
6610
圣诞树代码 下雪
相关推荐
java MD5 和 jsMD5 加密javajs引用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档