In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >
Share
Shulou(Shulou.com)06/01 Report--
First-class function: what is the first-class function of Lambda function and mapping?
You may have heard before that it is useful to speak a particular language because of its "first-class functionality". As I said in the first article in this series on functional programming, I don't agree with this popular view. I agree that first-class functions are a basic feature of any functional language, but I don't think this is a sufficient condition for language functionality. Many imperative languages also have this feature. But what is a first-class feature? When functions can be treated as any other value, functions are described as the first category-that is, they can be dynamically assigned to names or symbols at run time. They can be stored in data structures, passed in by function arguments, and returned as function return values.
This is not actually a novel idea. Function pointers have been a feature of C since 1972. Before that, procedure references were a feature of Algol 68, implemented in 1970, when they were considered a process programming feature. Back in time, Lisp (first implemented in 1963) was based on the concept that program code and data were interchangeable.
These are not vague functions either. In C, we usually use functions as the first kind of objects. For example, when sorting:
Char * * array = randomStrings ()
Printf ("before sorting:\ n"); for (int s = 0; s
< NO_OF_STRINGS ; s ++) printf("%s \ n",array [ s ]); qsort(array,NO_OF_STRINGS,sizeof(char *),compare); printf("排序后:\ n");for(int s = 0 ; s < NO_OF_STRINGS ; s ++) printf("%s \ n",array [ s ]); stdlibC中的库具有针对不同类型的排序例程的函数集合。所有的人都能够分拣任何种类的数据的:它们从编程器需要的唯一的协助将被提供,用于比较数据集的两个元素并返回的功能-1,1或者0,指示哪个元件比其它或更大他们是平等的。 这基本上是战略模式! 我们的字符串指针数组的比较器函数可以是: int compare(const void * a,const void * b){ char * str_a = *(char **)a ; char * str_b = *(char **)b ; return strcmp(str_a,str_b);} 并且,我们将它传递给排序函数,如下所示: qsort(array,NO_OF_STRINGS,sizeof(char *),compare); compare函数名称上没有括号使编译器发出函数指针而不是函数调用。因此,将函数视为C中的第一类对象非常容易,尽管接受函数指针的函数的签名非常难看: qsort(void * base,size_t nel,size_t width,int(* compar)(const void *,const void *)); 函数指针不仅用于排序。早在.NET发明之前,就有用于编写Microsoft Windows应用程序的Win32 API。在此之前,有Win16 API。它使得函数指针的自由使用可以用作回调。当应用程序需要通知已发生的某些事件时,应用程序在调用窗口管理器时由窗口管理器调用它时提供了指向其自身功能的指针。您可以将此视为应用程序(观察者)与其窗口(可观察对象)之间的观察者模式关系 - 应用程序接收到诸如鼠标点击和其窗口上发生的键盘按压等事件的通知。管理窗户的工作 - 移动它们,将它们堆叠在一起,决定哪个应用程序是用户操作的接收者 - 在窗口管理器中抽象。应用程序对与其共享环境的其他应用程序一无所知。在面向对象的编程中,我们通常通过抽象类和接口实现这种解耦,但也可以使用第一类函数来实现。 所以,我们一直在使用一流的功能。但是,可以公平地说,没有任何语言能够广泛宣传作为一等公民的功能而不是简单的Javascript。 Lambda表达式 在Javascript中,将函数传递给用作回调的其他函数一直是标准做法,就像在Win32 API中一样。这个想法是HTML DOM的组成部分,其中第一类函数可以作为事件侦听器添加到DOM元素: function myEventListener(){ 警报("我被点击了!")}...var myBtn = document。getElementById("myBtn")myBtn。addEventListener("click",myEventListener) 就像在C中一样,myEventListener在调用中引用函数名称时缺少括号addEventListener意味着它不会立即执行。相反,该函数与所click讨论的DOM元素上的事件相关联。单击该元素时,将调用该函数并发出警报。 流行的jQuery库通过提供一个函数来简化流程,该函数通过查询字符串选择DOM元素,并提供有用的函数来操作元素并向它们添加事件监听器: $("#myBtn")。click(function(){ 警报("我被点击了!")}) 第一类函数也是实现异步I / O的手段,用于XMLHttpRequest作为Ajax基础的对象。同样的想法在Node.js中也无处不在。当你想进行非阻塞函数调用时,你传递一个函数引用,让它在完成后重新打电话给你。 但是,这里还有其他的东西。其中第二个不仅仅是一流功能的例子。它也是lambda函数的一个例子。具体来说,这部分: function(){ 警报("我被点击了!");} lambda函数(通常称为lambda)是一个未命名的函数。他们本来可以称他们为匿名函数,然后每个人都会立即知道它们是什么。但是,这听起来并不令人印象深刻,所以lambda的功能就是它!lambda函数的关键是你需要在那个地方只有那里的函数; 因为在其他地方不需要它,你只需在那里定义它。它不需要名字。如果您确实需要在其他地方重用它,那么您可以考虑将其定义为命名函数并通过名称引用它,就像我在第一个Javascript示例中所做的那样。没有lambda函数,使用jQuery和Node编程确实非常烦人。 Lambda函数以不同的方式用不同的语言定义: 在Javascript中: function(a, b) { return a + b } 在Java中: (a, b) ->A + b
In C #: (a, b) = > a + b
In Clojure: (fn [a b] (+ a b))
In Clojure-shorthand version: # (+ 1 2)
In Groovy: {a, b-> a + b}
In F#: fun a b-> a + b
In Ruby, the so-called "stabby" syntax:-> (a, b) {return a + b}
As we have seen, most languages express lambda more succinctly than Javascript.
Map
You may have used the term "map" in programming to refer to data structures that store objects as key-value pairs (if your language calls it a "dictionary," that's fine-no problem). In functional programming, the term has another meaning. In fact, the basic concepts are actually the same. In both cases, one group of things is mapped to another. In the sense of data structure, a map is a noun-key mapped to a value. In a programmatic sense, mapping is a verb-function that maps an array of values to another array of values.
Let's say you have a function f and an array of values A = [a1magina2magina3magina4]. To map "F more than A" means to apply "F" to each component A:
A1 → f (A1) = A1'
A2 → f (a2) = a2'
A3 → f (A3) = A3'
A4 → f (A4) = a4'
Then, combine the resulting array in the same order as the input:
A'= map (fMaga A) = [a1, 2, 2, 5, 3, 3, 4, 4]
By example map
Okay, so it's interesting, but it's a little math. How often do you do this? In fact, it's much more frequent than you think. As always, an example explains things best, so let's take a look at a simple exercise I extracted from exercism.io when I was learning Clojure. This movement is called "RNA transcription", and it is very simple. We will look at the input string that needs to be converted to an output string. The translation of the base is as follows:
C → G
G → C
A → U
T → A
Any input other than C _ mae _ GI _ A _ T is invalid. The tests in JUnit5 might look like this:
Class TranscriberShould {
@ ParameterizedTest @ CsvSource ({"Cpeny G", "Greco C", "A Magi U", "TMagi A", "ACGTGGTCTTAA,UGCACCAGAAUU"}) void transcribe_dna_to_rna (String dna,String rna) {var transcriber = new Transcriber (); assertion (transcript). Transcription (dna), yes (rna);}
@ Test void reject_invalid_bases () {var transcriber = new Transcriber (); assertThrows (IllegalArgumentException. Class, ()-> scribe. Transcription ("XCGFGGTDTTAA");}}
Also, we can complete the test with this Java implementation:
Class Transcriber {
Private Map
< Character,Character >Pairs = new HashMap ()
Transcriber () {Yes. Put it ('Clearing last minute G'); that's right. Put ('Grain, last minute,'); yes. Put it ('Awayama'); that's right. Put ('Thousand Magnum');}
String transcribe (String dna) {var rna = new StringBuilder (); for (VAR base: DNA. ToCharArray () {if (right). ContainsKey (base)) {var pair = pair. To get (a foundation); rna. Append (pair);} others throw a new IllegalArgumentException ("not cardinality:" + cardinality);} returns rna. ToString ();}}
As expected, the key to functional style programming is to convert everything that may be expressed as a function into a function. So, let's do this:
Char basePair (char base) {if (pairs. Contains Key (base)) regression pairs. Get (foundation); others throw new IllegalArgumentException ("not foundation" + foundation);}
String transcribe (String dna) {var rna = new StringBuilder (); for (VAR base: DNA. ToCharArray () {var pair = basePair (base); rna. Append (pair);} returns rna. ToString ();}
Now, we can use the map as a verb. In Java, a function is provided in Streams API:
Char basePair (char base) {if (pairs. Contains Key (base)) regression pairs. Get (foundation); others throw new IllegalArgumentException ("not foundation" + foundation);}
String transcribe (String dna) {returns dna. CodePoints (). MapToObj (c-> (char) c). Map (base-> basePair (base)) Collect (StringBuilder:: new, StringBuilder:: append, StringBuilder:: append). ToString ();}
Hmmmm
So let's criticize this solution. The best thing about it is that the loop is gone. If you think about it, looping is a clerical activity, and we really shouldn't pay attention to it most of the time. Usually, we loop because we want to do something for each element in the collection. What we really want to do is take this input sequence and generate an output sequence from it. Streaming is responsible for the basic management of iterations for us. In fact, it's a design pattern-a functional design pattern-but I haven't mentioned its name yet. I don't want to scare you yet.
I have to admit that the rest of the code is not so good, mainly because the primitives in Java are not objects. The first point of non-greatness goes like this:
MapToObj (c-> (char) c)
We have to do this because Java handles primitives and objects differently, and although the language does have primitive wrapper classes, it cannot get a collection of Character objects directly from String.
Another less awe-inspiring thing is:
. Collect (StringBuilder:: new, StringBuilder:: append, StringBuilder:: append)
It's obvious why it's necessary to call append twice. I will explain later, but now is not the right time.
I won't try to defend this code-it's bad. If there is a convenient way to get Stream of Character objects from String, or even an array of characters, then there will be no problem, but we are not lucky. Dealing with primitives is not the best choice for FP in Java. Come to think of it, it's not even good for OO programming. So maybe we shouldn't be so obsessed with primitive people. What if we design it from the code? We can create an enumeration for the cardinality:
Enum Base {C _ Magi G _ A _ A _ T _ r U;}
Also, we have a class as a first-class collection that contains a series of basics:
Class Sequence {
List
< 基地>Base
Sequence (List
< Base >Bases) {this. Alkali = alkali;}
Stream
< Base >Bases () {return to base. Stream ();}}
Now, Transcriber looks like this:
Class Transcriber {
Private Map
< Base,Base >Pairs = new HashMap ()
Transcriber () {Yes. Put (C ~ (?) G); yes. Put (GMagna C); yes. Put (A Magi U); yes. Put (TMagna);}
Sequence transcription (sequence dna) {returns a new sequence (DNA). Base (). Map (pairs:: get). Collect (toList ());}}
This is much better. This pairs::get is a method reference; it refers to the method that get assigns to an instance of the pairs variable. By creating the type for the base, we design the possibility of invalid input, so the need for the basePair method disappears, and so does the exception. This is one of the advantages of Java over Clojure, which itself cannot enforce types in function contracts. More importantly, its StringBuilder has also disappeared. Java Streams works well when you need to iterate over collections, process each element in some way, and build a new collection that contains the results. This may be a large part of the cycle you write in your life. Most housekeeping is not part of the real work, but is done for you.
In Clojure
Without typing, Clojure is more concise than the Java version, and it gives us no difficulty in mapping string characters. The most important abstraction in Clojure is the sequence; all collection types can be treated as sequences, and strings are no exception:
(def to {\ C, "G",\ G, "C",\ A, "U",\ T, "A"})
(defn-base-pair [base] (if-let [pair (get pairs base)] pair (throw (IllegalArgumentException)). (str "not base:" base)
(define transcription [dna] (map base to dna))
The end of business of this code is the last line (map base-pair dna)-it's worth pointing out, because you may have missed it. It represents the base-pair function dna (represented as a sequence) of map on the string. If we want it to return a string instead of a list, that's what map requires, and the only change we need to make is:
(apply str (map base-pair dna))
In C#
Let's try another language. The necessary methods for the solution in C# are as follows:
Namespace RnaTranscription {Public Class Transcripter {private readonly Dictionary
< char,char >_ pairs = new Dictionary
< char,char >{# # * * $$} {{'Clearinghorn' G'}, {'Crundlemagorean' G'}, {'Aggregnant dagger'}, {'Aggregnant recorder U'}, {' Thumblemagery A'}}
Foreach (DNA in carbon b) rna of public string Transcribe (string dna) {var rna = new StringBuilder (); Append (_ pairs [b]); return rna. ToString ();}
Similarly, C # does not show us the problems we encountered in Java because strings in C # can be enumerated and all "primitives" can be treated as objects with behavior.
We can rewrite the program in a more practical way, like this, and it's much simpler than the Java Streams version. For "map" in the Java stream, read "select" in C #:
Public string Transcribe (string dna) {return String. Add ("", dna. Select (b = > _ pairs [b]);}
Or, if you prefer, you can use LINQ as its syntax sugar:
Public string Transcribe (string dna) {return String. Add ("", select _ pairs [b]) from the DNA in b;}
Why do we cycle?
You might get the idea. If you think about the time before writing the loop, you will usually try to do any of the following:
Map one type of array to another.
Filter by finding all the items in the array that satisfy a predicate.
Determines whether any item in the array satisfies certain predicates.
A count, sum, or other type of cumulative result in an accumulative array.
Sorts the elements of the array into a specific order.
The functional programming capabilities provided in most modern languages allow you to do all of this without writing loops or creating collections to store the results. Functional styles allow you to omit these housekeeping operations and focus on the actual work. More importantly, feature styles allow you to link actions together, for example, if you need:
Map the elements of an array to another type.
Filter out some mapped elements.
Sort filtered elements
In the imperative style, this requires multiple loops or a loop, which contains a lot of code. Either way, it involves the management of the true purpose of many fuzzy programs. In the functional style, you can get rid of administrative work and express yourself directly. Later, we'll see examples of how more versatile styles can make your life easier.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.