A deep understanding of the block concept in Ruby and a deep understanding of rubyblock
Block in Ruby is generally translated into code blocks, which seem a bit strange at the beginning, because there is no such thing in many languages. In fact, it is not bad.
First-class function and Higher-order function
The First-class function and Higher-order function are concepts in functional programming languages. They seem very simple to use.
First-class functions refers to a function that is a First-class citizen in some languages and can be passed as a parameter,
You can return a function, assign a value to a variable, and so on. That is, all functions that can be done by normal values can be used. JavaScript is like this. For example
CoffeeScript used in the sample code in JavaScript ):
Greet = (name)-> return-> console. log "Hello, # {name}" greetToMike = greet ("Mike") greetToMike () # => output "Hello, Mike" a = greetToMikea () # => output "Hello, Mike"
In the fourth row above, greet ("Mike") returns a function, so greetToMike () can be called in the fifth row to output "Hello, Mike ". The sixth row assigns a function to a, so the seventh row can call this function.
Higher-order function is generally translated into a higher-order function, which is a function that accepts a function as a parameter or returns a function.
A very common example (using JavaScript ):
a = [ "a", "b", "c", "d" ]a.map((x) -> x + '!') #=> ["a!", "b!", "c!", "d!"]
In the preceding example, map accepts an anonymous function as a parameter. Many methods in Array. prototype, such as reduce, filter, every, and some, are high-order functions, because they all accept functions as parameters.
High-order functions are very powerful and have a strong expressiveness, which can avoid repeated code. In general, it is a good thing.
The essence of Block
First, let's take a look at the comparison between a set of Ruby and CoffeeScript code.
a = [ "a", "b", "c", "d" ]a.map { |x| x + "!" } # => ["a!", "b!", "c!", "d!"]a.reduce { |acc, x| acc + x} # => "abcd"a = [ "a", "b", "c", "d" ]a.map((x) -> x + '!') # => ["a!", "b!", "c!", "d!"]a.reduce((acc, x) -> acc + x) # => "abcd"
These two sets of code really look like a super image. I think this also exposes the essence of Ruby block: A variant of function parameters of higher-order functions.
The map function in JavaScript accepts a function as a parameter, but the map in Ruby accepts
Block as a parameter.
In fact, matz mentioned the following in a book:
Copy codeThe Code is as follows: Finally, what is the block?
...
Blocks can also be seen as a special form of syntax for higher-order functions.
...
Higher-order functions are essentially the same as blocks.
...
In Ruby, functions are not first-class citizens and do not have first-class functions. But in Ruby
How to use high-order functions? The answer is to use block. Block or lambda can be used directly.
Or, you can use proc to convert a block to an instance of the Proc class.
I found that when block is used in Ruby, JavaScript can be used in almost all cases.
.
All methods in the Enumerable module are typical examples. In fact, the JavaScript version exists.
For example, Prototype. js has an Enumerable, which is almost the same as the Ruby version. Of course, it is implemented through higher-order functions.
What is the difference with higher-order functions?
Apart from Syntactic differences, there are two very important points.
Control flow operation
In the block, break, next, and so on can be used for control flow operations in a general loop.
It cannot be used in higher-order functions. For example, you can try using forEach in JavaScript instead of loop.
Implementing a take_while function is really awkward. For example, someone posted a post on cnode asking: Does node. js forEach not support break ?, In fact, the reply below in this post is basically wrong,
Some and every can use the features of short-circuit evaluation to crack down, but it is obviously unnatural and greatly increases the difficulty for others to understand the code.
From this point of view, the block is indeed good.
High-order functions with only one function parameter
In Ruby, a method can only accept one block as a parameter, which is probably similar to the higher order of only one function parameter.
Function. It seems that it is restricted. In fact, this book "The World of songben luhong's program" also explains a bit.
It probably refers to a survey. In the standard library of OCaml, which tends to use higher-order functions, 94%
The higher-order function has only one function parameter. Therefore, this restriction is not a problem. In my own experience, in JavaScript, higher-order functions that require two function parameters have never been used.
Unspecified
Well, this article looks a little too long, so I don't plan to write it down. In fact, there are some important points not to mention. For example
Block can actually be used as a closure. It is a little tragic when using def to define a method in Ruby, because it is not a closure, it is exposed
It does not contain any variables.
name = "mike"def greet puts "hello, #{name}"endhello # => in `greet': undefined local variable or method `name' for main:Object (NameError)
But block is enough.
name = "mike"define_method(:greet) do puts "hello, #{name}"endgreet # => "hello, mike"
There is no problem with JavaScript.
name = "mike"greet = -> console.log "hello, #{name}"greet() # => "hello, mike"
Similarly, the class and module keywords both create new scopes and cannot access external variables in them,
You can also use block to solve the problem.
There is also the difference between proc and lambda. In fact, I have never understood why lambda is not used.
And run to use proc, it is obvious that the return behavior of proc is too common sense. But in the end, I found
The behavior of the block is the same as that of the object created by proc, for example
def hello (1..10).each { |e| return e} return "hello"endhello # => 1
This is a bit sad.
Conclusion
So much has been said, because in Ruby, functions are not first-class citizens, and they want to get the convenience of functional programming.