# CH 10 First-class function: part 1
## First class function
### New skill
• Learn how to make first-class functions and values.
• Learn to wrap syntax using higher-order functions.
- Build complex calculations using chains of operations.
- Discover a way to operate on deeply nested data.
- Fontrol the ordering and repetition of actions to eliminate timing bugs.
• Apply two refactorings that use first-class and higher-order functions.
<!--
- 学习如何制作一流函数版本的语法。
- 学习使用高阶函数包装语法。
- 应用两个使用一流函数和高阶函数的重构方法。
-->
> These skills will be available once we learn about first-class values.
<!--
我们就可以学习一种功能性的迭代方式。我们可以利用运算链建立复杂的计算。我们可以发现一种对深度嵌套数据进行操作的方法。我们还可以学习控制动作的顺序和重复,以消除时间上的错误。我们将用两个架构来结束这个游戏,这两个架构可以让我们构造我们的服务。一旦我们学习了第一类值,这些技能就可以使用了。
-->
### First-class value
First-class values are anything that can be stored in a variable, passed as an argument, and returned from functions. A first-class value can be manipulated by code.
<!-- 一级值是任何可以存储在变量中、作为参数传递、并从函数中返回的东西。一级值可以被代码所操纵。 -->
- Many parts of a language are not first-class. We can wrap those parts in functions that do the same thing to make them first-class.
- Some languages have first-class functions that let you treat functions as first-class values. First-class functions are necessary for doing this level of functional programming.
- Higher-order functions are functions that take other functions as arguments (or that return a function).
<!-- - 一种语言的许多部分都不是一流的。我们可以将这些部分包裹在做同样事情的函数中,使它们成为一流的。
- 有些语言有一流的函数,让你把函数当作一流的值。一级函数对于进行这种层次的函数式编程是必要的。
- 高阶函数是以其他函数为参数的函数(或返回一个函数)。高阶函数让我们对不同的行为进行抽象。 -->
<!-- 在这一章中,我们将学习一种代码气味和两种重构方法,它们可以帮助我们消除重复,找到更好的抽象。我们将在本章和本书的整个第二部分中应用这些新技能。 -->
<!-- - 函数名中的隐式参数是一种代码气味,其中函数之间的差异在函数名中被命名。我们可以应用表达式隐式参数来使参数成为第一类,而不是函数名中不可访问的部分。
- 我们可以应用称为用回调替换主体的重构来抽象出行为。它创建了一个一流的函数参数,代表两个函数之间的行为差异。 -->
<!-- 代码气味:函数名称中的隐性参数 -->
- Code smell: Implicit argument in function name
- Implicit argument in function name is a code smell where the difference between functions is named in the function name. We can apply express implicit argument to make the argument first-class instead of an inaccessible part of the function name.
<!-- 重构。表达隐性参数 -->
- Refactoring: Express implicit argument
<!-- 重构。用回调取代主体 -->
- Refactoring: Replace body with callback
- Apply the refactoring called replace body with callback to abstract over behavior. It creates a first-class function argument that represents the behavioral difference between two functions.
## Code smell: Implicit argument in function name
There are two characteristics to the implicit argument in function name smell:
1. Very similar function implementations
2. Name of function indicates the difference in implementation
The function name difference is an implicit argument
<!-- 隐含参数在函数名称中的气味有两个特点。
1. 非常相似的函数实现
2. 函数的名称表明了实现的差异
函数名称差异是一个隐性参数 -->
## Refactoring: Express implicit argument
### Steps:
1. Identify the implicit argument in the name of the function.
2. Add explicit argument.
3. Use new argument in body in place of hard-coded value.
4. Update the calling code.
<!-- 这就是express这个词的意思。使隐式参数显性化。以下是具体步骤。 -->
<!-- 1. 确定函数名称中的隐性参数。
2. 添加显性参数。
3. 在主体中使用新的参数来代替硬编码的值。
4. 更新调用代码。
让我们看看我们如何重构setPriceByName(),它只能设置价格,变成setFieldByName(),它可以设置项目的任何字段。 -->
<!-- 这个重构应用于这段代码,用一个通用的函数取代了四个现有的函数,谁知道因为有了通用的setFieldByName(),有多少个函数不用写了。
我们所做的是使字段名成为一个一流的值。以前,字段名除了作为函数名的一部分隐含地暴露给API客户外,从未暴露给客户。现在,它是一个值(在本例中是一个字符串),可以作为一个参数传递,也可以存储在一个变量或数组中。这就是我们所说的第一类。我们可以使用整个语言来处理它。而使事物成为第一类是本章的主题。
你可能认为像这样使用字符串是不安全的。我们将在几页中讨论这个问题。现在,请随它去吧! -->


```ruby
# Usage example
employee = { id: 1, name: "John Doe", salary: 5000 }
department = { id: 2, name: "IT", multiplier: 1.2 }
# Before refactoring
def calculate_salary_for_employee_in_department(employee_id, department_id)
# Calculate salary based on employee and department information
# ...
end
calculate_salary_for_employee_in_department(employee[:id], department[:id])
# After refactoring
def calculate_salary(employee, department)
# Calculate salary based on employee and department information
# ...
end
# After refactoring
calculate_salary(employee, department)
```
### Examples of things you can do with a first-class value
1. Assign it to a variable.
2. Pass it as an argument to a function.
3. Return it from a function.
4. Store it in an array or object.
### Will field names as strings lead to more bugs?
```javascript
var validItemFields = ['price', 'quantity', 'shipping', 'tax'];
function setFieldByName(cart, name, field, value {
if(!validItemFields.includes(field))
throw `Not a valid item field: '${field}'.`;
var item = cart[name];
var newItem = objectSet(item, field, value);
var newCart = objectSet(cart, name, newItem);
return newCart;
}
```
### Will first-class fields make the API hard to change?
```javascript
var validItemFields = ['price', 'quantity', 'shipping', 'tax', 'number']
var translations = { 'quantity': 'number' };
function setFieldByName(cart, name, field, value) {
if(!validItemFields.includes(field))
throw "Not a valid item field: '" + field + "'.";
if(translations.hasOwnProperty(field))
field = translations[field];
var item = cart[name];
var newItem = objectSet(item, field, value);
var newCart = objectSet(cart, name, newItem);
return newCart;
}
```
<!-- before Replace body with callback -->
### For loop example: Eating and cleaning up
1. Wrap code in functions.
2. Rename to be more generic.
3. Express implicit argument.
4. Extract function.
5. Express implicit argument.


## Refactoring: Replace body with callback
1. Identify the before, body, and after sections.
2. Extract the whole thing into a function.
3. Extract the body section into a function passed as an argument to that function.



```ruby
# Usage example
employee = { id: 1, name: "John Doe", salary: 5000 }
department = { id: 2, name: "IT", multiplier: 1.2 }
# Before refactoring
def calculate_salary_for_employee_in_department(employee_id, department_id)
# Calculate salary based on employee and department information
employee = get_employee(employee_id)
department = get_department(department_id)
salary = employee[:salary] * department[:multiplier]
salary
end
calculate_salary_for_employee_in_department(employee[:id], department[:id])
# After refactoring
def calculate_salary(employee, department, salary_calculator)
# Before
# ...
# Body
salary_calculator.call(employee, department)
# After
# ...
end
# Proc
salary_calculator = Proc.new { |employee, department| employee[:salary] * department[:multiplier] }
# lambda
salary_calculator = ->(employee, department) { employee[:salary] * department[:multiplier] }
calculate_salary(employee, department, salary_calculator)
# Another refactoring
def salary_calculator(employee, department)
employee[:salary] * department[:multiplier]
end
calculate_salary(employee, department, method(:salary_calculator))
```
## Conclusion
This chapter introduced us to the ideas
- First-class values
- First-class functions
- Higher-order functions
> We are going to be exploring the potential of these ideas in the next chapters. After the distinction between actions, calculations, and data, the idea of higher-order functions opens up a new level of functional programming power. The second part of this book is all about that power.