当前位置:首页 » 编程软件 » 惰性求值编程

惰性求值编程

发布时间: 2022-05-24 07:47:06

㈠ C#函数式编程中的惰性求值详解

其实这个问题中有两个不正确的地方:
第一C#编程中所谓的函数其实是成员方法,函数是SP(面向过程编程中的术语,在面向对象中不存在这样的术语,只是很多程序员由SP转到OOP上,所以才有这种不规则的称呼)。有C#中没有独立到类之外的方法,也就是任何一个方法(包含静态成员方法)都是属于某个类或对象的。所以没有函数之称。
第二个是惰性其实并非C#术语,也非.net术语,勉强可算得上是面向对象的一种不规则称呼,因为C#其实是静态编译而非动态编译,直到.net 4。0之后才支持动态编译(只是支持),而所谓的惰性其实指的是运算的结果延迟到使用时才会加载。所以是后期绑定的一种特殊形式,(一般认为早期绑定是指编译态绑定,而后期绑定则是运行态绑定),所以在编程时应该理解什么时早期绑定,什么是后期绑定就可以了,而面各对象术语中还存在一种延迟加载的形式,就是所谓的“懒加载”又叫惰性加载。凡是具有这种特性的属性或运算结果的,也有人叫惰性加载。
在设计模式中有一个单例模式,其实有一种就是“懒汉模式”,在第一次使用时才会真实初始化实例。在linq to sql中的lumbda表达式中的,有一种IEnumable<T>的形式,执行的结果中其实并没有真正的结果,只有第一次引用该结果时才会真正加载结果,以供调用。类似延迟加载的模式就是所谓的情性加载,它的目的就是提高性能。
但是对于应用程序员来说,IQuery<T>和IEnumerable<T>是没有任何区别的,基本上不需要去判断两者的任何区别,而追求性能与各方面的其他考虑的设计师或是高程才会考虑到两者的具体的区别,所以基本上来说对于应用程序员不需要理解,只有高级程序员才会在性能上考虑诸多因素,如果内存等各方面原因时才会考虑到延迟加载。

java stream 及早求值

流使用的通用格式:
获得流对象Stream
对流对象Stream进行惰性求值,返回值仍然是一个Stream对象。
对流对象Stream进行及早求值,返回值不在是一个Stream对象。

㈢ 如何评价 Racket 这门编程语言

Racket的诞生与发展

简单介绍一下Racket的发展,详见知乎的一个关于Racket的问题回答:
1958年,人工智能之父John McCarthy 发明了一种以 Lambda 演算为基础的符号处理语言,1960年 McCarthy 发表着名论文Recursive Functions of Symbolic Expressions and Their Computation by Machine, 从此这种语言被命名为 LSIP (List Processor),其语法被命名为:符号表达式(S-Expression)。LISP构建在7个函数[atom car cdr cond cons eq quote]和2个特型[lambda label]之上。


Lisp诞生之初是为了纯粹的科学研究,代码执行像数学公式一样,以人的大脑来演算。直到麦卡锡的学生斯蒂芬·罗素将eval函数在IBM 704机器上实现后,才开启了Lisp作为一种计算机语言的历史。1962年,第一个完整的Lisp编译器在MIT诞生,从此之后Lisp以MIT为中心向全世界传播。之后十多年,出现了各种Lisp方言。


1975年,Scheme诞生。Scheme同样诞生与MIT,它的设计哲学是最小极简主义,它只提供必须的少数几个原语,所有其他的实用功能都由库来实现。在极简主义的设计思想下,Scheme趋于极致的优雅,并作为计算机教学语言在教育界广泛使用。


1984年,Common Lisp诞生。在二十世纪七八十年代,由于Lisp方言过多,社区分裂,不利于lisp整体的发展。从1981年开始,在一个Lisp黑客组织的运作下,经过三年的努力整合后,于1984年推出了Common Lisp。由于Scheme的设计理念和其他Lisp版本不同,所以尽管Common Lisp借鉴了Scheme的一些特点,但没有把Scheme整合进来。此后Lisp仅剩下两支方言: Common Lisp 和 Scheme。


从二十世纪九十年代开始,由于C++、Java、C#的兴起,Lisp逐渐没落。直到2005年后,随着科学计算的升温,动态语言JavaScript、python、Ruby的流行,Lisp又渐渐的回到人们的视线。不过在Lisp的传统阵地教育界,Python作为强有力的挑战者对Scheme发起冲锋;在2008年,MIT放弃了使用Scheme作为教学语言的SICP(计算机程序的构造和解释)课程,而启用Python进行基础教学。同时美国东北大学另立炉灶,其主导的科学计算系统PLT Scheme开始迅猛发展;2010年,PLT Scheme改名为Racket。近几年,The Racket Language连续成为年度最活跃语言网站,并驾齐驱的还有haskell网站。

符号表达式 S-Expression

首先说一下S表达式:S-表达式的基本元素是list与atom。list由括号包围,可包涵任何数量的由空格所分隔的元素,原子是其它内容。其使用前缀表示法,在Lisp中既用作代码,也用作数据。如:1+2*3 写成前缀表达式就是(+ 1 (* 2 3)) 。

优点:容易parse,简单纯粹,不用考虑什么优先级等,也是实现代码即数据的前提;

缺点:可读性不是很强;

高阶函数

高阶函数至少满足下列一个条件:

接受一个或多个函数作为输入;

输出一个函数;

微积分中的导数就是一个例子,映射一个函数到另一个函数。在无类型 lambda 演算中,所有函数都是高阶的。在函数式编程中,返回另一个函数的高阶函数被称为Curry化的函数。Curry化即把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。如 f(x,y)=x+y, 如果给定了 y=1,则就得到了 g(x)=x+1 这个函数。

Lambda 表达式

Racket中实用Lambda表达式来定义匿名函数,《如何设计程序》书中给出的使用原则是:如果某个非递归函数只需要当参数使用一次,实用Lambda表达式。如果想用Lambda表达式来表达递归,就需要引入Y组合子,Y 就是这样一个操作符,它作用于任何一个 (接受一个函数作为参数的) 函数 F,就会返回一个函数 X。再把 F 作用于这个函数 X,还是得到 X。所以 X 被叫做 F 的不动点(fixed point),即 (Y F) = (F (Y F)) 。

惰性求值

惰性求值(Lazy Evaluation),说白了就是某些中间结果不需要被求出来,求出来反而不利于后面的计算也浪费了时间。参见:惰性求值与惰性编程。
惰性求值是一个计算机编程中的一个概念,它的目的是要最小化计算机要做的工作。惰性计算的最重要的好处是它可以构造一个无限的数据类型。使用惰性求值的时候,表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值。语句如 x:=expression; (把一个表达式的结果赋值给一个变量)明显的调用这个表达式并把计算并把结果放置到 x 中,但是先不管实际在 x 中的是什么,直到通过后面的表达式中到 x 的引用而有了对它的值的需求的时候,而后面表达式自身的求值也可以被延迟,最终为了生成让外界看到的某个符号而计算这个快速增长的依赖树。

闭包

闭包在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。自由变量是在表达式中用于表示一个位置或一些位置的符号,比如 f(x,y) 对 x 求偏导时,y就是自由变量。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。在函数中(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。运行时,一旦外部的 函数被执行,一个闭包就形成了,闭包中包含了内部函数的代码,以及所需外部函数中的变量的引用。其中所引用的变量称作上值(upvalue)。网上有很多将JavaScript闭包的文章,如果你对LISP有系统的了解,那么这个概念自然会很清楚了。

快排的Racket实现

#langracket
(define(quick-sortarray)
(cond
[(empty?array)empty];快排的思想是分治+递归
[else(append
(quick-sort(filter(lambda(x)(<x(firstarray)))array));这里的array就是闭包
(filter(lambda(x)(=x(firstarray)))array)
(quick-sort(filter(lambda(x)(>x(firstarray)))array)))]))
(quick-sort'(132534509824))
;;运行结果'(012334455982)

通过这个例子,就可以感受到基于lambda算子的 Racket 语言强大的表达能力了,高阶函数、lambda表达式和闭包的使用是Racket所描述的快排十分的精炼,这和 基于冯诺依曼模型C语言是迥然不容的思维模式。后面,随着Racket 学习的进一步深入,尝试写一下解释器

㈣ python中and、or和not 三个逻辑运算符,一直理解不了,求帮助!

‘and’、‘or’和‘not’的优先级是not>and>or

㈤ F#是一种什么样的语言

F#是由微软发展的为.NET语言提供运行环境的程序设计语言,是函数编程语言,函数编程语言最重要的基础是Lambda Calculus。它是基于OCaml的,而OCaml是基于ML函数编程语言。有时F#和OCaml的程序是可以交互编译的。
F#已经接近成熟,支持高阶函数、柯里化、惰性求值、Continuations、模式匹配、闭包、列表处理和元编程。这是一个用于显示.NET在不同编程语言间互通的程序设计,可以被.NET中的任意其它代码编译和调用。

㈥ 惰性编程和惰性求值

惰性编程是一种将对函数或请求的处理延迟到真正需要结果时进行的通用概念。有很多应用程序都采用了这种概念,有的非常明显,有些则不太明显。从惰性编程的角度来思考问题,可以帮您消除代码中不必要的计算,也可以帮您重构程序以使之更加面向问题。

Scheme 中的简单惰性编程
惰性编程是这样一种技术:它可以将代码的求值延迟到需要结果值时再进行。例如,在 Scheme 中,惰性编程就是通过两个特殊的结构显式支持的。Scheme 的 delay 特殊表单接收一个代码块,它不会立即执行它们,而是将代码和参数作为一个 promise 存储起来。如果您 force 这个 promise 产生一个值,它就会运行这段代码。promise 随后会保存结果,这样将来再请求这个值时,该值就可以立即返回,而不用再次执行代码了。
下面是一个说明 delay 和 force 如何一起工作的简单例子。
清单 1. 使用 delay 和 force 的例子
;;The multiplication is saved but not executed
(define my-promise (delay (* 5 6 7 8 9)))

;;Again, saved but not executed
(define another-promise (delay (sqrt 9)))

;;Forces the multiplication to execute. Saves and returns the value
(display (force my-promise))
(newline)

;;This time, the multiplication doesn't have to execute. It just returns
;;the value that was previously saved.
(display (force my-promise))
(newline)

;;This proces an error, because the promise must be forced to be used
(display (+ my-promise (force another-promise)))
这些结构的使用都非常简单,但是它们应该用来干什么呢?一般地,惰性编程常用于所调用的函数生成调用程序不需要的值的情况下。例如,假设有一个函数会计算一组数字的平均值、方差和标准差。下面是实现这些功能的一种方法:
清单 2. 简单的统计计算
(define (square x) (* x x))
(define (calculate-statistics the-series)
(let* (
(size (length the-series))
(sum (apply + the-series))
(mean (/ sum size))
;variance is the sum of (x[i] - mean)^2 for all list values
(variance
(let* (
(variance-list (map (lambda (x) (square (- x mean))) the-series)))
(/ (apply + variance-list) size)))
(standard-deviation (sqrt variance)))
(vector mean variance standard-deviation)))

;Run the program
(display (calculate-statistics '(2 6 4 3 7 4 3 6 7 8 43 4 3 2 36 75 3)))
(newline)
现在假设我们希望只在特定条件下才会计算标准差,但是这个函数却早已花费了很多计算能力来计算标准差。有几种方法可以解决这个问题。您可以将其分割成几个单独的函数分别计算平均值、方差和标准差。不过,这样每个函数都必须重复计算平均值的过程。如果您同时需要这三个值,那么平均值就会被计算 3 次、方差会被计算 2 次、标准差会被计算 1 次。这中间有很多额外的不必要的工作。现在,您也可以要求将平均值传递给标准差函数,并强制用户为您调用平均值的计算函数。尽管这是可行的,但是这会产生一个非常可怕的 API:它的接口使用了太多特定于实现的内容。
使用惰性求值的一种较好的方法是将计算延迟:
清单 3. 利用惰性求值进行统计计算
(define (square x) (* x x))
(define (calculate-statistics the-series)
(let* (
(size (delay (length the-series)))
(mean (delay (/ (apply + the-series) (force size))))
;variance is the sum of (x[i] - mean)^2
(variance
(delay
(let* (
(variance-list (map (lambda (x) (square (- x (force mean))))
the-series)))
(/ (apply + variance-list) (force size)))))
(standard-deviation (delay (sqrt (force variance)))))
(vector mean variance standard-deviation)))

;Run the program
(define stats (calculate-statistics '(2 6 4 3 7 4 3 6 7 8 43 4 3 2 36 75 3)))
(define mean (force (vector-ref stats 0)))
(define variance (force (vector-ref stats 1)))
(define stddev (force (vector-ref stats 2)))
(display (list mean variance stddev))
(newline)
在这个版本的 calculate-statistics 中, 直到真正需要值时才会进行计算,并且同样重要的是,任何值都只会计算一次。如果您首先请求计算方差,它就会先计算平均值,并将其保存 下来,然后再计算并保存方差。如果接下来您请求计算平均值,因为平均值已经计算出来了,所以只需要简单地返回该值即可。如果您接下来请求计算标准差,它就会使用保存过的方差值,并通过此值来计算标准差。现在不会执行任何不需要的计算,函数的接口也得到了很好的保留。
在面向对象语言中,这种惰性编程方法也非常容易实现。在任何需要一组相关计算的地方,都可以创建一个类来保存中间值。构造函数接收所使用的初值,所有计算出来的值都被设置为空。这里不再使用 force,相反地,每个值都有一个 getter,它会检查该值是否为空;如果该值不为空,就执行计算。下面是 Java™ 语言中这种类的一个骨架:
清单 4. Java 语言中惰性求值的形式化表示
public class StatisticsCalculator {
private List the_series;
private Double mean;
private Integer size;
private Double variance;
private Double standard_deviation;
public StatisticsCalculator(List l)
{
the_series = l;
}
public int getSize()
{
if(size == null)
{
size = the_series.size();
}
return size;
}
public double getStandardDeviation()
{
if(stddev == null)
{
stddev = Math.sqrt(getVariance());
}
return stddev;
}
...
...
}
这个类本身可以作为一个多值的 promise 使用,实例变量中保留了计算的结果。每个函数都会通过查看变量值是否为空来确定代码是否已经执行过了。如果变量在需要时尚未有值,就执行代码并保存计算结果。注意如果 null 也在该值的有效值范围内,那么就需要一个辅助标志来说明代码是否已经执行过了,而不能简单地查看该值是否为空。
正如您所见,惰性编程技术可以用来为那些返回相关值的函数提供良好有效的 API。另外,在那些不直接支持惰性编程的语言中,惰性编程技术也可以通过类来实现。
不确定列表
假设您有一个由 5 的倍数组成的列表。现在您希望计算这个列表中所有数字的平方。最后,我们希望对计算结果进行遍历,并显示所有平方值小于 500 的数字。什么?您不能对一个无穷列表进行操作?为什么不行呢?
实际上,可能与直观的感觉相反,如果无穷列表基于一定的生成规则 ,那么无穷列表可能比有穷列表存储起来占用的空间更少。在上面这个例子中,原始列表是基于 X[i] = (i + 1) * 5 这条规则生成的,其中 X[i] 是列表在索引 i 处的值。 X[i] 也可以使用其前一个值来表示:X[i] = X[i-1] + 5; X[0] = 5。使用 Scheme 的 force 和 delay,就可以构造一个基于这条规则的数值流:
清单 5. 流的例子
;This is the generative rule for the list. It returns a pair
;with the car being the next value, and the cdr being a promise
;for the next pair
(define (my-generative-rule last-val)
(let (
;generative formula based on previous value
(next-val (+ last-val 5)))
;put the next value together with a promise for another one
(cons next-val (delay (my-generative-rule next-val)))))
;Since the cdr is a promise of a pair, rather than a pair itself,
;we have our own functions for getting the car and cdr.
(define (mystream-car the-stream) (car the-stream))
(define (mystream-cdr the-stream) (force (cdr the-stream)))

;Create our list
(define multiples-of-five (cons 5 (delay (my-generative-rule 5))))

;Display the fourth element of the list
(display (mystream-car (mystream-cdr (mystream-cdr (mystream-cdr multiples-of-five)))))
(newline)
现在,您希望计算所有数字的平方。要实现这种功能,需要一个函数从现有流和生成规则中创建一个新流 —— 这有点像 map,只不过它是针对流进行的。函数如下:
清单 6. 流的专用映射
(define (mystream-map function the-stream)
(cons
;;The first value will be the function applied to the car
(function (car the-stream))
;;The remaining values will be stored in a promise
(delay (mystream-map function (mystream-cdr the-stream)))))

(define squared-stream (mystream-map (lambda (x) (* x x)) multiples-of-five))

;Display the fourth element of this new list
(display (mystream-car (mystream-cdr (mystream-cdr (mystream-cdr squared-stream)))))
(newline)
现在,剩下的问题就是循环遍历该流,并打印结果值小于 500 的值:
清单 7. 循环遍历流
(let loop (
(remaining-stream squared-stream))
(if (>= (mystream-car remaining-stream) 500)
#f
(begin
(display (mystream-car remaining-stream))
(newline)
(loop (mystream-cdr remaining-stream)))))
显然,对于这种小程序来说,还有很多方法都可以更直接地实现这个目标。然而,即使在这个例子中,流也可以帮助我们较少地从实现角度来审视问题,而是更多地将问题当作一种抽象思想来看待。流让我们可以集中精力在问题 上,而不是在实现 上。流简化了与生成元素有关的算法的概念和实现。
到目前为止,我们所讨论的流对于学习流背后的概念来说都非常有用。然而,实现却可能会经受大量缺陷的折磨。首先,在很多场合下流都可能需要一个终结器。这种实现却并没有提供这种机制。另外,此处给出的这种流称为 odd stream,这种形式的流很容易实现。 但是这种流可能会导致所执行的计算量比所希望的多,因为列表中的值都会进行计算。标准流是在 SRFI-40 中定义的,它解决了这些问题以及其他一些问题(更多细节请参看 参考资料)。
回页首
跳过转换变量
到目前为止,我们所有惰性求值的例子都要求在进行计算之前必须完全实现中间值。部分原因是由于我们正在解决的问题的需求所导致的,另外一部分原因则是由于 delay 和 force 操作本身所带来的。例如,考虑下面的代码:
(define val1 20)
(define val2 30)
(define val3 40)
(define val4 0)
(define val5 (delay (* val1 val2)))
(define val6 (delay (* val4 val3)))
(define val7 (* (force val5) (force val6)))
在这个例子中,我们知道答案是 0,这是因为我们知道 0 乘任何次都是 0。因此,尽管这看上去似乎是可以使用惰性求值的情况(因为我们正在试图减少不必要的计算),但实际上使用 delay 和 force 并不能给我们提供什么帮助。
在这类情况下,为了不生成中间结果,需要一些特殊的惰性算法来延迟处理。我们需要实现对请求进行排队。然后,在请求最后结果时,它就可以在该队列中搜索那些可以帮助它对处理过程进行优化的值,然后使用这些值跳过对其他值的处理。在乘法的这个例子中,出现 0 就可以跳过所有的处理了。
下面是一个特殊的 delay/force 对,专门适用于乘法计算:
清单 8. 简单的专用 delay/force 对
;This will simply use a list to keep track of the values to be multiplied
(define (multiply-delay x y)
(let (
;convert to lists if they aren't already
(x-list (if (list? x) x (list x)))
(y-list (if (list? y) y (list y))))
;append them together
(append x-list y-list)))
(define (multiply-force mul-list)
(let (
(has-zero? #f))
(for-each
(lambda (x)
(if (eqv? 0 x)
(set! has-zero? #f)
#f))
mul-list)
(if has-zero?
0
(apply * mul-list))))
(define a (multiply-delay 23 54))
(define b (multiply-delay 0 5))
(define c (multiply-delay a b))
(define d (multiply-delay c 55)
(display (multiply-force d))
(newline)
然而,这个实现也有自己的问题。现在各个部分都不再是惰性的了,也不会再保存值了。为了实现一个优化,我们已经失去了原来的 delay 和 force 的优点。因此,我们不会保留一个所有参数的长列表,而是需要将它们放到各个 promise 中单独进行存放,这样我们就依然可以获得之前的优点。我们所需要的是一个说明该值是否已经计算的标记。如果该值已经计算过了,那么此处就只有一个不需要计算的元素了。否则,乘数和被乘数都会出现。新的代码如下:
清单 9. 另外一个专用的惰性结构
;Unevaluated promises will have the structure ('delayed val1 val2)
;Evaluated promises will have the structure ('forced result)

;Create an unevaluated promise
(define (multiply-delay x y)
(list 'delayed x y))

(define (multiply-force-nozero promise)
(if (pair? promise)
(if (eq? (car promise) 'forced)
;if the promise has been forced, just return the value
(cdr promise)
;otherwise, compute the value, and convert this into a "forced" promise
(begin
(set-car! promise 'forced)
(set-cdr! promise
(*
(multiply-force-nonzero (cadr promise))
(multiply-force-nonzero (caddr promise))))
;return the forced value
(cdr promise)))
;This is just a number, so return it
promise))
这个结构中有普通 delay/force 的所有优点。现在,由于乘法操作不管怎样都是一个相当快速的操作,因此这个完整的操作可能就有点浪费时间,不过它作为一个例子来说还是非常不错的。它对于执行代价更为昂贵的操作来说可以节省大量的时间,尤其是对于那些可能需要上下文开关或大量处理器资源的操作来说更是如此。
这种技术一种流行的用法是进行字符串的附加操作。它不用在每次进行附加操作时都分配新空间,而是只需要简单地维护一个需要进行连接的字符串行表。然后,当需要最终版本的字符串时,就只需要为这个新字符串分配一次空间。这样就节省了多个 malloc 调用,以及复制每个字符串的时间。
惰性求值
到现在为止,我们重点介绍的是非惰性语言中的惰性结构。然而,有些语言,例如 Haskell,会将一些惰性操作作为普通求值过程的一部分。这被称之为惰性求值。惰性求值中的参数直到需要时才会进行计算。这种程序实际上是从末尾开始反向执行的。它会判断自己需要返回什么,并继续向后执行来确定要这样做需要哪些值。基本上,每个函数都是使用对各个参数的 promise 来调用的。当计算需要值时,它就会执行 promise。由于代码只有在需要值时才会执行,因此这就称为按需调用。在传统编程语言中,传递的是值,而不是 promise,因此这就称为按值调用。
按需调用编程有几个优点。流是自动实现的。不需要的值永远也不会计算。然而,惰性程序的行为通常都很难预测。而在按值调用程序中,求值的顺序是可以预测的,因此任何基于时间或序列的计算都相当容易实现。在惰性语言中这就变得相当困难了,此时要描述具有明确顺序的事件就需要诸如 monads 之类的特殊结构。所有这些都使得与其他语言的交互变得十分困难。
有几种语言默认就会进行惰性编程,包括 Haskell 和 Clean。其他几种语言也有一些惰性版本,包括 Scheme、ML 等。

㈦ javascript 惰性求值

惰性编程是一种将对函数或请求的处理延迟到真正需要结果时进行的通用概念。有很多应用程序都采用了这种概念,有的非常明显,有些则不太明显。从惰性编程的角度来思考问题,可以帮您消除代码中不必要的计算,也可以帮您重构程序以使之更加面向问...

㈧ 最近有什么好看的电影吗求推荐

最近上映的《神奇女侠》《木乃伊》《变形金刚》和《小蜘蛛侠》都算是不错的商业影片,感兴趣的话推荐你去看看。

㈨ 什么是函数式编程思维

回答都有跑题,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也可以写函数式代码了

但是,这也只是本人积累得来的感悟,绝不敢大肆伸张这就是函数式,我也在不断研究中,如有问题,还望大神指正

㈩ mlranda中文是什么意思

1、Miranda, 人名,米兰达。
2、Miranda,一种编程语言,采用惰性求值的纯粹函数编程语言,由英国学者大卫·特纳(David Turner)所设计。采用来自ML语言与Hope语言的概念,他用此来作为他先前所设计的SASL语言与KRC语言的后继者。稍后发展出的Haskell语言,采用了很多由Miranda所发展出的概念。

热点内容
java返回this 发布:2025-10-20 08:28:16 浏览:647
制作脚本网站 发布:2025-10-20 08:17:34 浏览:939
python中的init方法 发布:2025-10-20 08:17:33 浏览:634
图案密码什么意思 发布:2025-10-20 08:16:56 浏览:823
怎么清理微信视频缓存 发布:2025-10-20 08:12:37 浏览:734
c语言编译器怎么看执行过程 发布:2025-10-20 08:00:32 浏览:1069
邮箱如何填写发信服务器 发布:2025-10-20 07:45:27 浏览:302
shell脚本入门案例 发布:2025-10-20 07:44:45 浏览:163
怎么上传照片浏览上传 发布:2025-10-20 07:44:03 浏览:855
python股票数据获取 发布:2025-10-20 07:39:44 浏览:765