在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
在柯里化中,一个函数接受一个参数并返回一个新的函数,这个新的函数接受下一个参数,依此类推,直到所有参数都被接受并最终返回结果。
在Scala
这样的支持函数式的编程语言,自带柯理化特性,
java
// 正常函数
// 定义一个接受两个参数的函数
def add(x: Int, y: Int): Int = x + y
// 使用原始的add函数
val result1 = add(3, 4)
println(s"Result of add(3, 4): $result1")
// 柯理化函数
// 使用柯里化版本的add函数
val result2 = curriedAdd(3)(4)
println(s"Result of curriedAdd(3)(4): $result2")
// 部分应用函数
val add3 = curriedAdd(3) _
val result3 = add3(4)
println(s"Result of add3(4): $result3")
Java里面我们需要依赖Java把里面的函数式接口去模拟柯理化
java
// 柯里化版本的add函数
public static Function<Integer, Function<Integer, Integer>> curriedAdd() {
return a -> b -> a + b;
}
// 使用柯里化版本的add函数
Function<Integer, Function<Integer, Integer>> curriedAdd = curriedAdd();
Function<Integer, Integer> add3 = curriedAdd.apply(3);
int result2 = add3.apply(4);
System.out.println("Result of curriedAdd(3)(4): " + result2);
// 进一步简化
int result3 = curriedAdd().apply(3).apply(4);
System.out.println("Result of curriedAdd(3)(4): " + result3);
C++里面我们也是借助lambda和函数包装器实现
cpp// 定义一个接受两个参数的函数
int add(int a, int b) {
return a + b;
}
// 柯里化版本的add函数
std::function<int(int)> curriedAdd(int a) {
return [a](int b) {
return add(a, b);
};
}
// 使用原始的add函数
int result1 = add(3, 4);
std::cout << "Result of add(3, 4): " << result1 << std::endl;
// 使用柯里化版本的add函数
auto add3 = curriedAdd(3);
int result2 = add3(4);
std::cout << "Result of curriedAdd(3)(4): " << result2 << std::endl;
// 进一步简化
int result3 = curriedAdd(3)(4);
std::cout << "Result of curriedAdd(3)(4): " << result3 << std::endl;
Kotlin里面我们可以通过返回函数的方法来实现柯理化
kotlin// 定义一个接受两个参数的函数
fun add(a: Int, b: Int): Int {
return a + b
}
// 柯里化版本的add函数
fun curriedAdd(a: Int): (Int) -> Int {
return { b -> add(a, b) }
}
fun main() {
// 使用原始的add函数
val result1 = add(3, 4)
println("Result of add(3, 4): $result1")
// 使用柯里化版本的add函数
val add3 = curriedAdd(3)
val result2 = add3(4)
println("Result of curriedAdd(3)(4): $result2")
// 进一步简化
val result3 = curriedAdd(3)(4)
println("Result of curriedAdd(3)(4): $result3")
}
在Golang
里函数是一等公民,可以通过返回函数来实现柯理化
go
// 定义一个接受两个参数的函数
func add(a int, b int) int {
return a + b
}
// 柯里化版本的add函数
func curriedAdd(a int) func(int) int {
return func(b int) int {
return add(a, b)
}
}
// 使用原始的add函数
result1 := add(3, 4)
fmt.Println("Result of add(3, 4):", result1)
// 使用柯里化版本的add函数
add3 := curriedAdd(3)
result2 := add3(4)
fmt.Println("Result of curriedAdd(3)(4):", result2)
// 进一步简化
result3 := curriedAdd(3)(4)
fmt.Println("Result of curriedAdd(3)(4):", result3)
Rust实现柯理化
rust// 定义一个接受两个参数的函数
fn add(a: i32, b: i32) -> i32 {
a + b
}
// 柯里化版本的add函数
fn curried_add(a: i32) -> impl Fn(i32) -> i32 {
move |b| add(a, b)
}
// 使用原始的add函数
let result1 = add(3, 4);
println!("Result of add(3, 4): {}", result1);
// 使用柯里化版本的add函数
let add3 = curried_add(3);
let result2 = add3(4);
println!("Result of curried_add(3)(4): {}", result2);
// 进一步简化
let result3 = curried_add(3)(4);
println!("Result of curried_add(3)(4): {}", result3);
js也可以很简单的实现柯理化
js // 定义一个接受两个参数的函数
function add(a, b) {
return a + b;
}
// 柯里化版本的add函数
function curriedAdd(a) {
return function(b) {
return add(a, b);
};
}
// 使用原始的add函数
const result1 = add(3, 4);
console.log("Result of add(3, 4):", result1);
// 使用柯里化版本的add函数
const add3 = curriedAdd(3);
const result2 = add3(4);
console.log("Result of curriedAdd(3)(4):", result2);
// 进一步简化
const result3 = curriedAdd(3)(4);
console.log("Result of curriedAdd(3)(4):", result3);
Haskell是FP语言的老大哥,函数都是默认柯理化
kotlin-- 定义一个接受两个参数的函数
add :: Int -> Int -> Int
add x y = x + y
-- 使用原始的add函数
result1 :: Int
result1 = add 3 4
-- 使用柯里化版本的add函数
add3 :: Int -> Int
add3 = add 3
result2 :: Int
result2 = add3 4
Python实现柯理化
pythondef add(a, b):
return a + b
def curried_add(a):
def inner(b):
return add(a, b)
return inner
add3 = curried_add(3)
print(add3(4)) # 输出: 7
上面就是大部分主流语言实现柯理化的思路,观察所有语言实现思路可以得知,尽管有的语言函数不是一等公民,还有的语言内置柯理化特性,但是实现柯理化的思路都是:定义一个接受部分参数并返回一个新函数的函数。
观察以上的例子我们也可以得出柯理化的作用,参数复用(预设参数),延迟执行
还有一个特性是函数组合,我们可以将多个函数组合起来
jsconst compose = (f, g) => x => f(g(x));
const add1 = x => x + 1;
const multiplyBy2 = x => x * 2;
const add1ThenMultiplyBy2 = compose(multiplyBy2, add1);
console.log(add1ThenMultiplyBy2(3)); // 输出: 8
好啦,现在实践吧!
之前没学FP的时候不了解什么是柯理化,现在学了FP,才知道柯理化无处不在,就比如说Go后端场景
go
// 例1
type Logger func(string)
func NewLogger(level string) Logger {
return func(message string) {
fmt.Printf("[%s] %s\n", level, message)
}
}
func main() {
errorLogger := NewLogger("ERROR")
infoLogger := NewLogger("INFO")
errorLogger("Something went wrong!")
infoLogger("Everything is fine.")
}
// 例2
type HTTPRequest func(string) ([]byte, error)
func NewHTTPRequest(method string, headers map[string]string) HTTPRequest {
return func(url string) ([]byte, error) {
req, err := http.NewRequest(method, url, nil)
if err != nil {
return nil, err
}
for key, value := range headers {
req.Header.Add(key, value)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}
}
func main() {
getRequest := NewHTTPRequest("GET", map[string]string{"User-Agent": "Go-http-client/1.1"})
response, err := getRequest("https://api.github.com")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Response:", string(response))
}
// 例3
type QueryFunc func(string) ([]map[string]interface{}, error)
func NewQueryFunc(db *sql.DB) QueryFunc {
return func(query string) ([]map[string]interface{}, error) {
rows, err := db.Query(query)
if err != nil {
return nil, err
}
defer rows.Close()
columns, err := rows.Columns()
if err != nil {
return nil, err
}
results := []map[string]interface{}{}
for rows.Next() {
values := make([]interface{}, len(columns))
pointers := make([]interface{}, len(columns))
for i := range values {
pointers[i] = &values[i]
}
if err := rows.Scan(pointers...); err != nil {
return nil, err
}
result := make(map[string]interface{})
for i, colName := range columns {
val := values[i]
result[colName] = val
}
results = append(results, result)
}
return results, nil
}
}
func main() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
fmt.Println("Error connecting to database:", err)
return
}
defer db.Close()
queryFunc := NewQueryFunc(db)
results, err := queryFunc("SELECT * FROM users")
if err != nil {
fmt.Println("Error executing query:", err)
return
}
for _, result := range results {
fmt.Println(result)
}
}
其实这些算是柯理化
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!