‘壹’ 输入m*n阶矩阵A和B,用函数编程实现两个函数相加和相乘
输入m*n阶矩阵A和B,用C语言编程实现两个函数相加和相乘:
一、矩阵相乘。程序中先初始化矩阵,然后判断第一个矩阵的列数和第二个矩阵的行数是否相等,如果不相等则直接提示错误后退出程序。相等的话则利用公式计算乘积,结果赋给matrix二维数组。最后用for循环打印出结果验证。
#include<stdio.h>
#include<stdlib.h>
#define M 100
int main(void)
{
int i,j,k,matrix1[M][M],matrix2[M][M],row1,col1,row2,col2,matrix[M][M];
printf("输入第一个矩阵的行数和列数:");
scanf("%d%d",&row1,&col1);
printf("输入第一个矩阵: ");
for(i=0;i<row1;i++){
for(j=0;j<col1;j++){
scanf("%d",&matrix1[i][j]);
}
}
printf("输入第二个矩阵的行数和列数:");
scanf("%d%d",&row2,&col2);
printf("输入第二个矩阵: ");
for(i=0;i<row2;i++){
for(j=0;j<col2;j++){
scanf("%d",&matrix2[i][j]);
}}
for(i=0;i<row1;i++){
for(j=0;j<col2;j++){
matrix[i][j]=0;
} }
if(col1!=row2){
fprintf(stderr,"enput error!");
exit(EXIT_FAILURE);
}
printf("The result: ");
for(i=0;i<row1;i++){
for(j=0;j<col2;j++){
for(k=0;k<col1;k++){
matrix[i][j]=matrix[i][j]+matrix1[i][k]*matrix2[k][j];
} } }
for(i=0;i<row1;i++){
for(j=0;j<col2;j++){
printf("%d ",matrix[i][j]); }
printf(" "); }
return 0;}
二、矩阵相加:
#include<stdio.h>
#define M 20
#define N 20
float A[M][N];
float B[M][N];
float C[M][N];
int i,j,m,n,p,q;
float y=1.0;
void main()
{
scanf("%d,%d",&i,&j);
printf("请输入矩阵B的行数和列数(用逗号隔开):");
scanf("%d,%d",&m,&n);
if(i!=m||j!=n)
printf("***对不起,您输入的两个矩阵不能相加,请重试.*** ");
else printf("请输入矩阵A: ");
for(p=0;p<i;p++)
for(q=0;q<j;q++)
scanf("%f",&A[p][q]);
printf("输出矩阵A: ");
for(p=0;p<i;p++)
for(q=0;q<j;q++)
{
printf("%10.2f",A[p][q]);
if((q+1)%j==0)
printf(" ");
}
printf("请输入矩阵B: ");
for(p=0;p<i;p++)
for(q=0;q<j;q++)
scanf("%f",&B[p][q]);
printf("输出矩阵B: ");
for(p=0;p<i;p++)
for(q=0;q<j;q++)
{
printf("%10.2f",B[p][q]);
if((q+1)%j==0)
printf(" ");
}
printf("矩阵A+矩阵B为: "); //计算两个矩阵相加
for(p=0;p<i;p++)
for(q=0;q<j;q++)
C[p][q]=A[p][q]+B[p][q];
for(p=0;p<i;p++)
for(q=0;q<j;q++)
{
printf("%10.2f",C[p][q]);
if((q+1)%j==0)
printf(" ");
}
};
‘贰’ OCaml 4.08.0 发布,函数式编程语言
OCaml(Objective Caml) 4.08.0 发布了。OCaml 是 Caml 编程语言的主要实现,Caml 是函数式编程语言,OCaml 将 Caml 语言在面向对举塌象方面做了延展,它的扩展语言还有基于微软 .net 平台的 F# (fsharp) 语言。Caml 的代码大多可以在 F# 中使用。
此版本更新亮点包括:
绑定运算符(let*、let+、and* 等),它们可用于简化一元代码。
`open`现在适用于结构中的任意模块表达式和签名中的应用路径。
(用户定义的)“警报”的新概念概括了已弃用的警告。
标准库中的新模块:Fun、Bool、Int、Option、Result。
Float 中的大量新功能,包括 FMA 支持和新的 Float.Array 子模块。
在批处理模式下突出显示错误和警告链陆的来源。
许多错误消息得到了棚答顷改进。
改进了对象和惰性值的 AFL 检测。
‘叁’ 为什么要用函数式编程
以 C 语言源程序为例,使用函数式的编程风格主要是有利于程序的调试!而且程序的可读性也很好。程序思路很清楚!!以下面的源程序进行讲解就一目了然了。在以下题目中,三次用到了求阶乘的代码(A!、(A-B)!、B!),现在使用调用子函数的编程风格,程序简洁明了、且可读性很强。如果不使用函数式编程,那么求阶乘的代码你就必须要重复三次。你说到底是哪一种编程风格好呢?
例如:求组合数C(A,B) = A!/( (A-B)! * B! )
int jie_cheng( int ) ;
void main( )
{
int a = 0,b = 0 , c = 0 ;
scanf("%d %d",&a,&b);
c = jie_cheng(a) / (jie_cheng(a-b)*jiecheng(b)) ;
printf("Zu he shu C is: %d\n", c);
}
int jie_cheng(int num)
{
if( num == 1)
return 1 ;
else
return num*jie_cheng(num-1) ;
}
‘肆’ 前端必学-函数式编程(六)
我们前篇谈了很多关于【闭包】的理解了,所以你应该会知道,我们现在将要谈的就是 ——【异步】。
我们为什么觉得“异步问题”复杂呢?
其中很重要的一个原因是 —— 时间!时间将我们对数据的操判运作、管理,变复杂了好几个量级!
(需要特别提出并明确的是: 异步和同步之间是可以相互转化的! 我们使用异步或者同步取决于 —— 如何使代码更加可读!)
函数式编程给出了实现“代码更可读”的落地原则(已多次回顾):
所以我们可以期待,异步在函数式编程中的表现!
上代码:
onCustomer(..) 和 onOrders(..) 是两个【回调函数】释义,两者执行的先后顺序并不能确定,所以它是一个基于时间掘唤梁的复杂状态。
释义:回调函数其实就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。
通常来说,我们最先想到的是:把 lookupOrders(..) 写到 onCustomer(..) 里面,那我们就可以确认 onOrders(..) 会在 onCustomer(..) 之后运行。
这样写,对吗?
不对!因为 onCustomer(..) 、 onOrders(..) 这两个回调函数的关系更像是一种竞争关系(都是赋值 customer.orders ), 它们应该并行执行 , 而不是串行执行 。
即:我不管你们谁先执行,谁先执行完,谁就赋值给 customer.orders !
那我们的思路应该是:
不过,这样让代码又变得更加难阅读!!函数内部赋值依赖于外部变量、甚至受外部回调函数的影响。
那究竟怎么办呢?
最终,我们借用 JS promise 减少这个时间状态,将异步转成同步:
两个 .then(..) 运行之前, lookupCustomer(..) 和 lookupOrders(..) 已被同步调用,满足并行执行,谁先结束,谁赋值给 customer.orders ,所以我们不需要知道谁先谁后!
在这样的实现下,不再需要时间先后的概念!减少了时间状态!!代码的可读性更高了!!
这是一个 积极的数组 ,因为它们同步(即时)地操作着离散的即时值或值的列表/结构上的值。
什么意思?
a 映射到 b,再去修改 a ,b 不会收到影响。
而这,是一个 惰性的数组 , mapLazy(..) 本质上 “监听” 了数组 a,只要一个新的值添加到数组的末端(push(..)),它都会运行映射函数 v => v * 2 并把改变后的值添加到数组 b 里。
什么意思?
a 映射到 b,再去修改 a ,b 也会修改。
原来,后者存在 异步 的概念。
让我们来想象这样一个链樱数组,它不只是简单地获得值,它还是一个懒惰地接受和响应(也就是“反应”)值的数组,比如:
设置“懒惰的数组” a 的过程是异步的!
b ,是 map 映射后的数组,但更重要的是,b 是 反应性 的,我们对 b 加了一个类似监听器的东西。
这里直接给出解答:
这里再多小结一句:时间让异步更加复杂,函数式编程在异步下的运用就是减少或直接干掉时间状态。
想象下 a 还可以被绑定上一些其他的事件上,比如说用户的鼠标点击事件和键盘按键事件,服务端来的 websocket 消息等。
上述的 LazyArray 又可叫做 observable !(当然,它不止用在 map 方法中)
现在已经有各种各样的 Observables 的库类,最出名的是 RxJS 和 Most 。
以 RxJS 为例:
不仅如此,RxJS 还定义了超过 100 个可以在有新值添加时才触发的方法。就像数组一样。每个 Observable 的方法都会返回一个新的 Observable,意味着他们是链式的。如果一个方法被调用,则它的返回值应该由输入的 Observable 去返回,然后触发到输出的 Observable里,否则抛弃。
比如:
本篇介绍了【异步】在函数式编程中的表现。
原则是:对于那些异步中有时态的操作,基础的函数式编程原理就是将它们变为无时态的应用。即 减少时间状态 !
就像 promise 创建了一个单一的未来值,我们可以创建一个积极的列表的值来代替像惰性的observable(事件)流的值。
我们介绍了 RxJS 库,后续我们还会介绍更多优美的 JS 函数式编程库!
(俗话说的好,三方库选的好,下班都很早!!)
现在本瓜有点明白那句话了:看一门语言是不是函数式编程,取决于它的核心库是不是函数式编程。
也许我们还不熟悉像 RxJS 这类库,但我们慢慢就会越来越重视它们,越来越使用它们,越来越领会到它们!!
异步,以上。
‘伍’ 什么是函数式编程思维
回答都有跑题,show概念之嫌,题主问的是函数式思维,这个问题我一直在思考,毕竟是方法论,能力有限,只能从切身实践告诉你
1.表达式化
在
最初的时候,需要转变观念,去可变量,去循环,把命令式改成表达式,注意,这只是把你丢在荒山野岭让你感受一下,离开熟悉的环境,地球依然在转,但是有个
重点,那就是一切都是表达式; 为什么是表达式呢?这个问题就像为什么鱼在水里?
因为函数式建立在lambda演算之上而非图灵机,只不过两者被证明等价,所以你可以在你的机器上跑全是表达式的代码,就如有人证明天空适合鱼生存,所以
鱼可以在天上游
当你接受了鱼可以在天上游之后,就该上正餐了
1.5 数据与行为分离
这也是和面向对象不一致的地方,面向对象强调数据与行为绑定,但函数式不是,确切的说函数式 函数与数据等价,所以你才可以将函数当参数与返回值,你在设计时,切勿让数据自己长腿能跑,其次,行为必须消除副作用,不可以偷偷把数据改了,习惯第一条后,应哗亏耐该不会的
2.高阶逻辑
用
了函数式,就不要在想循环,赋值这些低阶逻辑了,而应该更高阶的思考问题,这比转化表达式更难,函数式又叫声明式,也就是你要做什么,只要说一下就行,而
非写个遍历,做个状态判断,空枣用函数式你不需要考虑这些,你不知道函数式的列表是怎么遍历的,中间向两边?
从后往前?这也是为何函数式适合并发的原因之一,你想知道列表中大于3的数有多少,只要,list.count(_ > 3)
而不是写循环,你可以直接写你的业务,不要拘泥于细节,有点像sql, 你需要什么告诉电脑就行,你或许会问,count foreach filter
这些函数怎么来的? 因为有了他们你才不需要写循环,他们把你留在高阶逻辑中乱春,这个问题的答案请看下面
3.组合子逻辑 或又叫 自底向上的设计
函
数式和OO是反的,面向对象是自顶向下的设计,函数式是自底向上的设计,也就是先定义最基本的操作,然后不断组合,不断堆积以满足你的所有需要,如sql
定义了select, from, where...这几个组合子,来满足你的查询需求,同理函数式语言会提供foreach,
map等组合子(操作)来满足你的需求,所以你必须自下而上的设计你的代码结构,并且满足你的需求,当你只用组合子写代码时,你会发现你写的全是高阶逻辑
如
果这些已有组合子满足不了你,你就得自己写,foreach不行,你就自己写递归,我告诉你,递归背后也是组合子,这里一些'大神'应该不知道,在图灵机
里,递归就是方法不断调用自己没什么好说的,但是在lambda演算中,匿名函数是没法调用自己的,所以递归是用Y组合子(又叫不动点组合子)把递归函数
自己求解出来再调用的,这才可以实现递归,并与图灵机的循环等价,有点跑题了,总之要想顺手的写函数式,最好用面向组合子的设计,注意,不是必须,组合子
演算和lambda演算可以相互转化,也就是,你完全可以写一堆杂乱的表达式,但没有组合子逻辑来得清爽,Haskell大规模使用monad这个特殊组
合子,始其变得统一整洁
好了,总结一下
函数式思维,其实就是组合子逻辑,用简单的几个函数组合来构建复杂逻辑,始终以高阶的角度去表达问题,而非依赖副作用。
知道这点,你用java也可以写函数式代码了
但是,这也只是本人积累得来的感悟,绝不敢大肆伸张这就是函数式,我也在不断研究中,如有问题,还望大神指正
‘陆’ JS函数式编程和递归探索:路由树的操作
开始切入正题之前,有必要告知大家一下,这篇文章可能有一些深度,初学者可能理解会有些吃力。我会尽量把复杂问题简单化,争取让每个阅读的童鞋们都能看得懂。希望你对element-ui,vue-router,KeepAlive组件有一点了解。现在,我们开始吧液态碧。
熟悉element-ui的童鞋们都知道,ElMenuItem和ElSubMenu都需要一个闹举index属性,该属性必须是唯一的。现在,我们想把路由配置直接应用于ElMenu,该如何确保index的唯一性呢?我们需要有一个生成唯一index的函数。如下是genKey函数的定义,是不是很简单?
现在,我们创建addRouteMetaKey函数,该函数对路由树进行递归遍历,为每一个路由配置的meta属性动态添加key字段。这个函数很简单,属于最基础的递归使用例子,我就不做太多解释了。
提示 :数组的forEach方法不是纯函数,因为它有副作用,所以forEach方法不能称之为函数式编程工具。
通过addRouteMetaKey函数,我们可以把路由的meta.key作为index的值了。
现在,我们想实现另一个功能,就是 基于标签页的路由组件缓存控制 。使用过Vuejs KeepAlive组件的童鞋们,应该多多少少都遇到一些坑吧?在我们的项目中,有一个顶部标签页导航,每个tab项对应一个url,以每个url对应路由的title作为tab项标题,当切换tab的时候加载缓存中的url对应的路由组件,关闭tab项,下次打开该路由url,重新挂载对应的路由组件,而不是从缓存中加载。
当路由层级不确定的时候,KeepAlive会变的难以手动控制。所以,我 剑走偏锋,尝试了一种简单的解决方案 ,实践证明: 这是非常有效的 。我的方案就是把无限层级的路由树转化为一维数组。通过为meta添加必要的字段,进行页面结构个性化定制。
我们需要把每层路由配置的path转化为全路径,所以需要一个函数:getRouteFullPath,该函数定义如下:
getRouteFullPath函数中使用到的joinPath函数用于将多个路径字符串拼接为1个完整的路径,定义如下:
现在,我们把路由树转化为一维数组。我们定义toFlatRoutes函数,该函数使用了数组的rece方法对路由树进行聚合递归,将路由配置中的path属性的值替换为全路径,还顺便给路由配置添加了name属性,返回一个新的一维路由配置数组。 这是函数式编程和递归结合的一个例子。
以上,我们解决了KeepAlive的缓存控制问题;现在,我们又有了一个新的用户体验上的需求,就是我们想根据url对应的路由,自动展开该路由meta.key所属的侧边菜单;我们通过查阅element-ui文档得知,ElMenu有一个open方法,接收index作为参数,展开index对应的菜单。
现在的问题是,我们的路由对应的index是ElMenuItem的,而路由树已经被我们转化为了一维数组,通过路由的matched字段是得不到我们想要的菜单index的。所以, 我们需要遍历原始路由树 。
如下代码,我们定义getMenuKey函数,该函数接收的参数为route对象。如果路由存在,我们进行查找。首先进行简单查找,如果找到一个菜单menu,闭大则返回该菜单的meta.key;如果简单查找无果,则对路由树进行递归查找; 这是函数式编程和递归结合的另一个例子。
现在,我们大功告成了;以上就是本节的知识点,童鞋们理解了吗?只要我们熟悉递归的使用,其实操作树很简单。如果大家还有不懂的,可以评论区问我。感谢阅读!
‘柒’ Scala语言的主要应用领域与作用
Scala的特性
1.面向对象特性
Scala是一种纯面向对象的语言,每一个值都是对象。对象的数据类型以及行为由类和特征(Trait)描述。类抽象机制的扩展有两种途径。一种途径是子类继承,另一种途径是灵活的混入(Mixin)机制。这两种途径能避免多重继承的种种问题。
2.函数式编程
Scala也是一种函数式语言,其函数也能当成值来使用。Scala提供了轻量级的语法用以定义匿名函数,支持高阶函数,允许嵌套多层函数,并支持柯里化。Scala的CaseClass及其内置的模式匹配相当于函数式编程语言中常用的代数类型(AlgebraicType)。
更进一步,程序员可以利用Scala的模式匹配,编写类似正则表达式的代码处理XML数据。在这些情形中,顺序容器的推导式(comprehension)功能对编写公式化查询非常有用。
由于JVM不支持尾部递归,Scala也不能完全支持尾部递归优化。不过,在简单的情况下,Scala编译器可以把尾部递归优化成循环。
4.静态类型
Scala是具备类型系统,通过编译时的检查,保证代码的安全性和一致性。类型系统具体支持以下特性:
泛型类,型变注释(VarianceAnnotation),类型继承结构的上限和下限,把类别和抽象类型作为对象成员,复合类型,引用自己时显式指定类型,视图,多态方法。
5.扩展性
Scala的设计承认一个事实,即在实践中,某个领域特定的应用程序开发往往需要特定于该领域的语言扩展。Scala提供了许多独特的语言机制,可以以库的形式轻易无缝添加新的语言结构:
任何方法可用作前缀或后缀操作符,可以根据预期类型自动构造闭包。联合使用以上两个特性,使你可以定义新的语句而无须扩展语法也无须使用宏之类的元编程特性。
5.使用Scala的框架
Lift是一个开源的Web应用框架,旨在提供类似RubyonRails的东西。因为Lift使用了Scala,所以Lift应用程序可以使用所有的Java库和Web容器。
scala语言主要应用领域
cala运行于JVM之上,并且它可以访问任何的java类库并且与java框架进行互操作,scala也大量重用了java类型和类库。
大数据的开发语言是Scala的原因:
1:大数据的本身是计算数据,而Scala即有面向对象组织项目工程的能力,又有计算数据的功能。
2:现在大数据事实上的计算标准框架Spark,它是用Scala开发的,因为计算数据,Scala它是函数式编程,它实现算法非常简洁优雅。
例:kafka,它是一个消息中间件,如果外部数据要流进大数据中心,我们一般都要用kafka作适配器,那如果大数据中心的数据流到外部,也是用kafka(如Spark计算的数据要交给HBASE或MySql,期间我们都会用kafka),很多的大数据组件都是用的Scala编写的,所以,如果你想成为一个较高级的大数据开发高手,你一定要掌握Scala。
‘捌’ 阐述函数编程的最新发展动态是什么
函数式编程语言的兴冲激渣起:随着函数式编程范式的流行,越来越多的函数式编程语言被开发和应用,例如Clojure、Scala、Haskell等。这些语言具有高度的抽象和表达能力,能够提高程序的可读性和可维护性。
函数式编程的并行化:由于函数式编程强调函铅数数之间的独立性和无状态性,因此函数式编程非常适合并行化处理。近年来,越来越多的函数式编程框架和库被开发出来,能够方便地实现并行化处理,提高程序的性能和效率。
函数式编程与人工智能的结合:函数式编程的特点使其非常适合处理人工智能领域的问题。近年来,越来越多的人工智能工具和库开始采用函数式编程的范式,例如TensorFlow、PyTorch等。
函数式编程与大数据的结合:函数式编程对数据的处理非常方便,因此在大数据领域中也受到越来越多的关注。例如,Spark和Flink等大数据框架中采用了函数式编程的思想,提高了程序的可读性和可维护性。
函数式编程与区块链的结合:区块链是一个去中心化的分布式账本系统,其中智能合约是一个重要的功能。智能合约通常使用函数式散悄编程语言进行编写,例如Solidity语言,以确保合约的安全和正确性。
‘玖’ 函数在编程中扮演着什么样的作用
函数在编程中的作用:
支持闭包和高阶函数,支持惰性计算(lazy evaluation)。使用递归作为控制流程的机制。加强了引用透明性。没有副作用。我将重点放在在 Java 语言中使用闭包和高阶函数上,但是首先对上面列出的所有特点做一个概述。
闭包和高阶函数
函数编程支持函数作为第一类对象,有时称为 闭包或者 仿函数(functor)对象。实质上,闭包是起函数的作用并可以像对象一样操作的对象。与此类似,FP 语言支持 高阶函数。高阶函数可以用另一个函数(间接地,用一个表达式) 作为其输入参数,在某些情况下,它甚至返回一个函数作为其输出参数。这两种结构结合在一起使得可以用优雅的方式进行模块化编程,这是使用 FP 的最大好处。
惰性计算
除了高阶函数和仿函数(或闭包)的概念,FP 还引入了惰性计算的概念。在惰性计算中,表达式不是在绑定到变量时立即计算,而是在求值程序需要产生表达式的值时进行计算。延迟的计算使您可以编写可能潜在地生成无穷输出的函数。因为不会计算多于程序的其余部分所需要的值,所以不需要担心由无穷计算所导致的 out-of-memory 错误。一个惰性计算的例子是生成无穷 Fibonacci 列表的函数,但是对 第 n 个Fibonacci 数的计算相当于只是从可能的无穷列表中提取一项。
递归
FP 还有一个特点是用递归做为控制流程的机制。例如,Lisp 处理的列表定义为在头元素后面有子列表,这种表示法使得它自己自然地对更小的子列表不断递归。
函数的优点:
1.代码简洁,开发快速
函数式编程大量使用函数,减少了代码的重复,因此程序比较短,开发速度较快。
Paul Graham在《黑客与画家》一书中写道:同样功能的程序,极端情况下,Lisp代码的长度可能是C代码的二十分之一。
如果程序员每天所写的代码行数基本相同,这就意味着,"C语言需要一年时间完成开发某个功能,Lisp语言只需要不到三星期。反过来说,如果某个新功能,Lisp语言完成开发需要三个月,C语言需要写五年。"当然,这样的对比故意夸大了差异,但是"在一个高度竞争的市场中,即使开发速度只相差两三倍,也足以使得你永远处在落后的位置。"
2. 接近自然语言,易于理解
函数式编程的自由度很高,可以写出很接近自然语言的代码。
前文曾经将表达式(1 + 2) * 3 - 4,写成函数式语言:
subtract(multiply(add(1,2), 3), 4)
对它进行变形,不难得到另一种写法:
add(1,2).multiply(3).subtract(4)
这基本就是自然语言的表达了。再看下面的代码,大家应该一眼就能明白它老戚哪的意思吧:
merge([1,2],[3,4]).sort().search("2")
因此,函数式编程的代码更容易理解。
3. 更方便的代码管理
函数式编程不依赖、也不会改变外界的状态,只要给定输入参数,返回的结果必定相同。因此,每一个函数都可以被看做独立单元,很有利于进行单元测试(unit testing)和除错(debugging),以及模块化组合。
4. 易于"并发编程"
函数式编程不需要考虑"死锁"(deadlock),因为它不修改变量,所以根本不存在"锁"线程的问题。不必担心一个线程的数据,被另一个线程修改,所以侍码可以很放心地把工作分摊到多个线程,部署"并发编程"仔枣(concurrency)。
请看下面的代码:
var s1 = Op1();
var s2 = Op2();
var s3 = concat(s1, s2);
由于s1和s2互不干扰,不会修改变量,谁先执行是无所谓的,所以可以放心地增加线程,把它们分配在两个线程上完成。其他类型的语言就做不到这一点,因为s1可能会修改系统状态,而s2可能会用到这些状态,所以必须保证s2在s1之后运行,自然也就不能部署到其他线程上了。
多核CPU是将来的潮流,所以函数式编程的这个特性非常重要。
5. 代码的热升级
函数式编程没有副作用,只要保证接口不变,内部实现是外部无关的。所以,可以在运行状态下直接升级代码,不需要重启,也不需要停机。Erlang语言早就证明了这一点,它是瑞典爱立信公司为了管理电话系统而开发的,电话系统的升级当然是不能停机的。