00:00
我们发现SC这门语言,因为它有函数式编程的特性,所以呢,它其实相比Java而言增加了很多新的特性,这些特性其实非常的强大,可以实现很多Java做不到的功能,比如说这里的传名参数,Java里面没有这样的概念,那么呃,Java里面自然也就没有所谓的控制抽象了,有了这些概念,Skyla其实就可以做更多的事情,比如说可以做什么呢?啊,接下来我们可以举一个例子啊,我们可以直接用控制抽象传名参数的这种。特性去实现一个自定义的while循环的功能啊,也就是说我们可以自定义函数实现while这个关键字的功能了。好,接下来我们来看一看怎么样去实现啊。New有一个scale的object,目前是TEST12,现在我们算是一个具体的应用案例啊,我把它叫做my well自己实现一个自定义的well循环啊,那首先我们先来回忆一下常规的well循环是怎么样写的,首先Y循环的话,我们必须要有一个循环变量,这个变量呢,是在Y循环外部定义出来的啊,所以接下来我们定义,而且这个必须是Y对吧?呃,我们要更改它的值嘛,比方说定义一个N,我们定义一个十嘛。
01:22
然后接下来我们先写一个常规的while循环,也就是用while关键字去实现的一个循环,也就是while当前的N,如果要是比方说啊,我们要就是把当前的这一个代码printline要打印,要要循环十次啊,那就如果它等于等于一的话,再来我们就直接print line n,然后就N减一对吧,呃,N减减,我们就是N等于一,这样的话就可以看到。
02:00
十九八七六五四三二一的十个输出,这是非常简单的一个应用,那现在如果我们想自己定义一个函数实现while关键字的功能的话,该怎么去做呢?哇,这个听起来不可思议啊,怎么能自定义函数实现这个关键字的功能呢?诶,这个还真不是完全做不到,为什么呢?因为大家发现接下来我们这个well在定义的过程当中使用它的时候,主要其实就是干什么呢?主要是不是就是传,首先一个传一个条件。然后其次传什么,传外循环的这个循环体传一段代码。那如果我们要把它这个拆开来看的话,我们如果把Y要看成一个自定义的函数,那后边是不是就相当于是分步传入的两个参数啊。哎,那所以首先整体的这个函数定义,那就应该是之前我们颗粒化的那种定义的方式了啊,或者我们要是直接用这个B包实现的话,那就是实现两层啊,就是外边先传第一层这个参数,这个参数应该是一个条件。
03:04
然后呢,得到的这个结果应该是一个函数,这个函数呢,再去传一个参数,后面要传的参数呢,就是他要执行真正要执行的后面这一段代码。所大家其实发现了,前边和后边我们要传的都是一段代码,所以这个函数的参数,这不就是我们前面说的传名参数吗?要把代码块作为参数直接传入吗?啊,那接下来我们就来给大家先做一个基本的实现。那这里边呃,做这样的一个实现,我们把这个基本结构是定义出来了啊,啊,我们就是可以用一包直线一个函数,那这是基本的思路啊,就是将代码块作为参数传入,那这里大家会发现,因为Y循环,我们是要实现循环的这个功能的啊,那接下来我们怎么样就是具体调用它的时候能变成一个循环的过程呢?
04:11
那对于这个函数式编程语言而言,当然实现循环就是用递归了,哎,所以当前这个例子其实是把我们之前讲的很多东西都糅合在一起了,这是一个非常好的应用案例啊,就一方面我们可以看一看之前关于这个币包的用法,另外呢,我们还考虑到了这个传名参数啊,接下来呢,我们还用到了递归啊,那所以接下来我们是这个递归调用,我们直接做一个实现吧,EF my well。首先啊,外层的这个函数,我们说它要传入的是一个条件,那所以我把它叫做condition,那有同学可能想到这condition应该是一个什么样的类型呢?那这就是一个板类型嘛,对吧?当前我这传的不就是一个布尔类型的值吗?
05:05
大家注意,这里边不能直接给一个布尔类型的值啊,有同学可能想我先给一个布尔类型的值先放在这儿,在这儿我们先试一试啊,看看有有什么问题,那么把这一个第一个参数传进来之后,它得到的返回值应该又是一个函数啊,啊,这个函数可能比较难写,我们先空在这儿先看啊里面的具体实现,然后接下来我们就知道了内层函数。内层函数,那就需要需要递归调用。并且我们这里边知道的参数就是。循环体,循环体里边我们要执行的代码不是内存函数的参数啊,那这里边我们再定一个,既然是要内层函数,是要做这个DV调用,直接执行循环嘛,我们就把它叫做do loop吧,里面的之前的参数我们就把它叫做要执行的操作op,那这个那就是一个代码块了,就没什么好说的,而且我们知道对于Y循环而言,它的这个代码块不需要有任何的返回值啊,所以这个代码块我们就定义成unit,返回类型是unit啊,就是这样的一个定义啊,传名参数,然后接下来我们就自然知道了啊,里边的这个循环当然也不需要有任何返回值了,Unit里边执行的时候怎么执行呢?那就是if当前的condition。
06:41
Condition,如果目前的condition为true的话,我们就去执行当前的op这段代码,对吧?也把op放在这儿进行一遍。哦,接下来怎么办呢?啊,接下来那自然就是要进一步的去处理。
07:02
递归调用继续执行当前的这个代码对吧?那至于说这个当前的呃,循环变量怎么样更改,这个都应该是在我们的执行的这个循环体代码里边实现的,哎,所以在这里边就会把这个循环变量进行一个更改,那这里边其实大家就发现问题了,因为接下来我应该怎么样呢,还是要调用自身对不对,实现这个循环嘛,也就继续my well well,这里边呢,它传入的肯定还是condition啊,是这样一个condition对不对,然后后边还是一个op,那这样的话就有问题了,如果前面我们这里边condition就是一个布尔类型的值的话。那最初我们判断的这个,比方说我们传一个N大于等于一,它如果一开始的值是大于等于一的话,那我们这里边是传值参数啊,那就是相当于就是就是一个处,那接下来是不是永远它都为处啊,那接下来他就永远执行下去了,永远不会不调用这个,呃,就是永远都走的是if这个分支,永远都在调用自身。
08:03
我们事实上想的是什么呢?我们想的是执行了op之后,当前的循环变量去需要去做更改,更改完了之后呢,再去判断一下这个当前的condition条件,看它到底是不是为true,所以大家会发现当前的condition呢,并不是要直接计算出,现在是一个除号false的值,直接把这个值传进来,后面继续用,而是说要传这个表达式。所以当前我们就看到了,这里不是传布尔类型的值,而是要传一个代码块,只不过这个代码块返回值是一个布尔类型,所以目前我们其实是这样的一个类型,把它写成这样就对了。好的,那接下来我们就看到后边啊,If的话是这样去做操作,那如果要是else,如果这个condition为false不为真的话,那怎么办呢?那也非常简单,啥都不要执行,退出不就完了吗?哎,所以当前这个do lo就直接结束了,那我们在外面这个my well到底是要干什么呢?当然就是要直接去直,就是返回当前do loop的这个函数体,对吧?那所以这里边我们要把这个函数体一个定义啊,但但大家也可以直接用这个下划线的形式啊,这个定义的更加的明确一点,呃,那我们前面这儿要把它的类型直接写出来。
09:26
当前的类型,那就应该是。大家看参数类型是一个。是一个代码框对吧,是它的参数类型让大家看的清楚,我把这个括起来,然后呢,呃,因为它返回的是函数嘛,所以我们又要有这个拉姆达表达式的这个箭头,返回值类型是unit,哎,所以这个可能稍微会会复杂一点,需要把这个搞清楚,当前的我们定义的my well,自定义的well循环啊,它是一个函数。那么它的函这个函数的参数呢,是我们这里边的条件,条件是作为一个代码块传进来的,然后它有返回值,它的返回值呢,是另外一个函数,这是它的内层函数作为返回值返回的,而内层函数呢,啊呃,就是我我们是以后边的这个代码块执行的循环体的代码作为参数。
10:23
进行执行的里边还需要做一个递归调用,根据当前的条件condition去做一个判断,那所以整个这个实践逻辑确实相对来讲还是有一点复杂的啊啊我们就是这样的一个实现啊,接下来我们可以利用这个my well来做一个来来做一个书写啊,大家可以看一看,实现了这个my well之后,我们调用的时候应该怎么调用呢?按照前面的这个想呃想法啊,当然现在这个N已经我们这个减完了之后啊,不停的减已经要变成零了,所以在这个调用之前是先把这个N重新做一个负值,然后接下来调用的时候,那就是还是一样N,看这个判断条件不就是N大于等于一吗?大于等于一在这个条件下,然后接下来怎么样呢?呃,大家知道后边这里也是用的时候要传第二个参数嘛啊,那这里边给大家一个写法,就是如果里边是一个代码块的话,那外层的小括号也是可以省略掉的啊。所以我刚。
11:24
这就直接把它写成这个画括号的形式了,那大家看这个书写其实是不是就跟我们之前这个是一模一样的呀。啊,完整的调用的话,应该是这里有一个小括号,我们说这个小括号是可以省略的啊,那所以接下来这样的写法后跟之前带有关键字的写法和用方式完全一样了,我们看看用结果是不是完全一样。大家看到没有问题,十九八七六五三二一,完整的一个while循环就这样实现了啊,这是呃,就是我们利用了前面所学过的很多知识啊,包括了控制抽象这里边我们用了这个传代码块啊,传名参数,另外呢,还用到了B包,呃呃,再再另外一个还用到了这个递归的一个调用方式,就可以实现这样一个功能,非常的强大。
12:14
那当然了,前面这种写法比较还是稍微的复杂了一点,如果要是稍微简单一些的话,我们可以把它做一个化简,OK,首先里边既然是用到了B包,然后我们是把外边,呃,就是外层函数是要返回内层函数这个函数体,那自然内层函数可以写成一个,写成一个拉姆达表达式了啊,我们直接先做一个匿名函数的表达,用匿名函数直线,那当前df my well,我们把这个叫做my well2吧,还是直接copy一下之前的这个实现啊,我们直接在上面一些更改就可以得到最后的结果。Y2,那这里我们知道,既然内层函数是要直接返回的,那干脆啊,不需要名称了。
13:09
Loop要去掉,因为它叫什么名不关心,我们只要定义一个拉姆达表达式定义声明出来,然后直接把这一行返回不就完了吗?哎,所以直接op,既然是拉姆达表达式类型也不用写了,对吧?啊,那后边这里就。所有的类型都不用写,后边直接给一个前的这个箭头表示,这是一个拉姆达表达式就可以了啊,然后里边做的计算,那就是if condition,然后执行当前的op操作,在里边呢,再调一个,注意这里也改成MY2。规的调用当前深,然后把K和op再传进来啊,这样一改就改完了,因为所有的类型都在外边定义好了嘛,那同样我们可以测试一下,看看当前的这个效果一样不一样啊,我们可以在前面加一个分界线。
14:02
同样,还是先把N的值要改回成十,里边我们调用YY2。看到这个没有问题,还是十九八七六五三二一啊,每一次输出都是一样啊,那自然大家就想到了,还可以进一步进一步做简化呀,这个匿名函数,这还不是最简单的表示,我们知道既然使用到了B包,那最简单的写法其实是颗理化的写法啊,那所以这里边我们可以必须用用。理化实现。这里定义一个my well3。那如果要是可体化实现的话,这里我们直接就是先写一个第一个参数,它的类型是传名参数,传一个哪块进来,返回的是板类型的值,然后后边会有第二层级的参数,我们直接在这定义出来,And是op,也是一个文明参数,这一个返回unit类型的的一个代码块啊,那所以这其实就是把我们前面的两个。
15:14
这里定义的这两个参数放在一起了嘛,直接跟在后边了,然后接下来最后它的返回类型是什么呢?类型其实就是我们内部函数返回的这个类型unit嘛,什么都没有,就是返回一个空就完了,里边具体的实现不实现呢,非常简单,是不是直接实现这一段就可以了,判断当前的这个condition,然后执行它。接着提归调用MY3把condition和op传进来,大家看,如果要是用颗理化去实现的话,这就太简单了,我们只要看清楚当前要实现的这一个函数啊,MY的这个函数它需要的参数是两段代码,那接下来我们就按照这样的逻辑直接定义出来,做一个递归调用,直接就可以把它搞定。
16:04
啊,对应的,我们可以继续做一个测试。里我们调用my well3看一下得到结果是否还是一样。看到完全一样,诶,所以这四种实现的方式最后是完全等价的,我们就用之前所学过的所有的知识,实现了一个自定义的while循环。大家可以把这个作为一个综合的练习,复习一下之前的所有内容。
我来说两句