了解函数式编程:从表象到本质,从技法到心法

今天看到,《代码整洁之道》(Clean Code)和《架构整洁之道》(Clean Architecture)的作者Robert C. Martin在讨论函数式编程时曾提到:

函数式编程不仅仅是“用函数编程”。函数式编程是没有赋值语句的编程。

一旦你尝试不用赋值语句编程,函数式编程的所有其他特性就水到渠成了。你要处理函数,就必须用递归,所有这些东西在你决定不用赋值的那一刻,就自然而然地形成了。所以说,函数式编程就是这么回事。 ——《函数式设计》,Robert C. Martin

于是,萌发了写一篇聊函数式编程文章的想法。

初识函数式编程

函数式编程(Functional Programming, FP)是一种基于数学函数计算的编程范式。它强调使用纯函数、不可变性和高阶函数来解决问题。本文将通过代码示例和概念解释,带你深入了解函数式编程的核心思想和应用场景。

案例:简单的累加求和

在大部分情况下,循环可以直接用递归来代替:

传统过程式编程实现

def sum_numbers(n):sum = 0for i in range(1, n + 1):sum += ireturn sumprint(sum_numbers(5))  # 输出 15

函数式编程实现

def sum_numbers_functional(n):if n == 1:return 1else:return n + sum_numbers_functional(n - 1)print(sum_numbers_functional(5))  # 输出 15

在这个例子中,通过递归的方式实现了累加求和的功能。没有使用任何赋值语句来更新状态,而是通过每次递归调用自己来逐步累积结果。

案例: 计算斐波那契数列

通常来说,算法都有递推+(iterative)和递归(recursive)两种定义,递推符合我们日常生活的思维模式,递归则是符合函数式编程的思维模式。这两种定义,也对应了下面的传统过程式编程实现和函数式编程实现。

传统过程式编程实现

def fibonacci(n):fib = [0, 1]for i in range(2, n + 1):fib.append(fib[i - 1] + fib[i - 2])return fib[n]print(fibonacci(10))  # 输出 55

函数式编程实现

def fibonacci_functional(n):if n <= 1:return nelse:return fibonacci_functional(n - 1) + fibonacci_functional(n - 2)print(fibonacci_functional(10))  # 输出 55

在这个例子中,我们同样没有使用任何赋值语句来更新状态,而是通过递归来实现斐波那契数列的计算。需要注意的是,这种方法虽然展示了函数式编程的思想,但在实际应用中,递归方法可能不是最优的选择,因为它会导致大量的重复计算。为了解决这个问题,我们可以引入尾递归优化或使用辅助函数来缓存中间结果。

使用尾递归优化斐波那契数列

函数式编程实现(带尾递归)
def fibonacci_tail_recursive(n, a=0, b=1):if n == 0:return aelif n == 1:return belse:return fibonacci_tail_recursive(n - 1, b, a + b)print(fibonacci_tail_recursive(10))  # 输出 55

在这个更复杂的例子中,我们引入了尾递归来优化斐波那契数列的计算。尾递归是一种特殊的递归形式,其中递归调用是函数体中的最后一个操作。这使得编译器或解释器可以在递归调用之前释放当前栈帧,从而防止堆栈溢出。这里使用了两个累积参数 ab 来传递计算的状态,而不是直接修改变量的值。需要注意的是,Python默认并不支持尾调用优化,但在支持尾调用优化的语言中,这种方法可以大大提高程序的效率。


深入函数式编程

函数式编程的几个核心概念:

  1. 纯函数(Pure Functions)

    • 纯函数的输出仅取决于输入参数,没有副作用。相同的输入总是产生相同的输出,并且不修改任何外部状态。
  2. 不可变性(Immutability)

    • 在函数式编程中,一旦创建了一个数据结构,就不能更改它的状态。所有数据都是不可变的,这意味着一旦创建了一个对象或变量,就不能直接修改它的内容,只能通过创建新的数据结构来表示状态的变化。
  3. 高阶函数(Higher-Order Functions)

    • 函数可以作为参数传递给其他函数,也可以作为其他函数的返回值。高阶函数允许我们编写抽象级别更高的代码,使得代码更加模块化和可复用。
  4. 递归(Recursion)

    • 函数式编程中经常使用递归来实现循环逻辑,而不是使用传统的循环结构。递归是一种自然的方式来表达重复的任务,特别是在处理树形结构或分治算法时。
  5. 惰性求值(Lazy Evaluation)

    • 惰性求值是指只有在真正需要的时候才计算表达式的值。这可以提高效率,特别是在处理大量数据时,因为不需要一次性加载所有数据。

为什么能去掉状态的存储?

函数式编程之所以能够去掉状态的存储,主要是因为:

  • 避免了副作用(Side Effects):在函数式编程中,函数不会修改外部状态,这就消除了许多传统编程模式中的不确定性和调试难度。
  • 不变性(Immutability):使用不可变的数据结构可以简化编程模型,因为不必担心数据会在不经意间被修改。
  • 并行性(Concurrency):由于函数式编程中的函数不依赖于外部状态,也不修改外部状态,因此多个函数可以安全地并行执行,无需担心数据竞争条件。

函数式编程的限制

虽然函数式编程有许多优点,但它并不是适用于所有场景的银弹。以下是一些限制和注意事项:

  1. 性能开销

    • 在某些情况下,频繁创建新数据结构可能会导致性能下降。例如,在大规模数据处理中,如果频繁地复制数组或列表,可能会导致内存使用和计算时间的增加。
  2. 递归深度限制

    • 在一些语言中,特别是那些没有尾调用优化(Tail Call Optimization)的语言,如Python,递归可能导致栈溢出。
  3. 学习曲线

    • 对于习惯了命令式编程的开发者来说,理解和掌握函数式编程的概念和技巧可能需要一定的时间。
  4. 调试困难

    • 在某些情况下,由于缺乏显式的状态跟踪,调试函数式程序可能会比调试命令式程序更具挑战性。
  5. 生态系统兼容性

    • 如果你的项目依赖于特定的库或框架,而这些库或框架并没有充分支持函数式编程,那么完全采用函数式编程可能会遇到兼容性问题。

总的来说,函数式编程提供了一种强大的编程范式,可以简化代码、提高代码的可读性和可维护性,但在实际应用中需要根据具体情况权衡其利弊。在实际开发中,结合函数式编程和其他编程范式(如面向对象编程、命令式编程)通常是更灵活的做法。


进一步深入,探讨函数式编程的本质

通过前面几个例子,我们看到许多算法都能转换为函数式编程思想的实现。那么,函数式编程思想的本质是什么?

由于 函数式的优势是:具有不变性从而能避免副作用,具有并行性的优点
因此 函数式编程技术的本质是:为了达到纯函数的要求,利用技术手段将非纯函数转换为纯函数的技术
达到纯函数的技术内涵是问题分解。
因此 函数式编程思想的本质是:问题分解


技术手段实现纯函数

刚刚提到,了达到纯函数的要求,可以利用技术手段将非纯函数转换为纯函数。那么有哪些常见的技术手段将普通函数转换为纯函数呢?

递归实现纯函数

递归是一种非常强大的技术,它通过自我调用来解决更小规模的相同问题,直到达到可以直接解决的基本情况。

  1. 递归实现阶乘

    def factorial(n):if n == 0:return 1else:return n * factorial(n - 1)print(factorial(5))  # 输出 120
    
  2. 递归实现斐波那契数列

    def fibonacci(n):if n <= 1:return nelse:return fibonacci(n - 1) + fibonacci(n - 2)print(fibonacci(10))  # 输出 55
    
  3. 递归实现树的遍历

    data Tree a = Leaf | Node a (Tree a) (Tree a)sumTree :: Tree Int -> Int
    sumTree Leaf = 0
    sumTree (Node value left right) = value + sumTree left + sumTree rightmain = print (sumTree (Node 1 (Node 2 Leaf Leaf) Leaf))  -- 输出 3
    

递归与其他形式的问题分解

递归是问题分解的一种常见形式,但问题分解还包括分治法、分批处理等其他形式。

  1. 分治法(Divide and Conquer)

    def merge_sort(arr):if len(arr) <= 1:return arrmid = len(arr) // 2left = merge_sort(arr[:mid])right = merge_sort(arr[mid:])return merge(left, right)def merge(left, right):result = []while left and right:if left[0] < right[0]:result.append(left.pop(0))else:result.append(right.pop(0))result.extend(left or right)return resultarr = [3, 1, 4, 1, 5, 9, 2, 6]
    print(merge_sort(arr))  # 输出 [1, 1, 2, 3, 4, 5, 6, 9]
    
  2. 分批处理(Chunk Processing)

    def process_large_data(data, batch_size=1000):results = []for i in range(0, len(data), batch_size):batch = data[i:i + batch_size]processed_batch = map(process_item, batch)results.extend(processed_batch)return resultsdef process_item(item):# 处理单个项的逻辑return item * 2large_data = list(range(1, 1001))
    processed_data = process_large_data(large_data)
    print(processed_data[:10])  # 输出 [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
    

其他技术手段实现纯函数

  1. 高阶函数(Higher-Order Functions)

    numbers = [1, 2, 3, 4, 5]
    squared = map(lambda x: x**2, numbers)
    print(list(squared))  # 输出 [1, 4, 9, 16, 25]
    
  2. 组合函数(Function Composition)

    def square(x):return x ** 2def add_one(x):return x + 1def compose(f, g):return lambda x: f(g(x))composed = compose(square, add_one)
    print(composed(3))  # 输出 16 (因为 (3 + 1)**2 = 16)
    
  3. 柯里化(Currying)

    def curry(f):return lambda x: lambda y: f(x, y)def add(x, y):return x + ycurried_add = curry(add)
    add_five = curried_add(5)
    print(add_five(3))  # 输出 8
    
  4. 模式匹配(Pattern Matching)

    sumList [] = 0
    sumList (x:xs) = x + sumList xsmain = print (sumList [1, 2, 3])  -- 输出 6
    
  5. 代数数据类型(Algebraic Data Types)

    data Tree a = Leaf | Node a (Tree a) (Tree a)depth :: Tree a -> Int
    depth Leaf = 0
    depth (Node _ left right) = 1 + max (depth left) (depth right)main = print (depth (Node 1 (Node 2 Leaf Leaf) Leaf))  -- 输出 2
    

通过结合递归和其他技术手段,我们可以更好地理解函数式编程的核心思想,并将其应用于实际编程任务中。


函数式编程技巧在我们日常编程活动中也很常见

函数式编程技巧在日常编程活动中非常常见,并且这些技巧不仅限于专门的函数式编程语言。下面通过具体的例子展示如何在日常编程中使用函数式编程技巧,如 mapfilter 等。

使用 map

map 是一种常见的高阶函数,用于将一个函数应用到集合中的每一个元素,并返回一个新的集合。

numbers = [1, 2, 3, 4, 5]# 使用 lambda 表达式
squared = map(lambda x: x**2, numbers)
print(list(squared))  # 输出 [1, 4, 9, 16, 25]# 使用定义的函数
def square(x):return x**2squared = map(square, numbers)
print(list(squared))  # 输出 [1, 4, 9, 16, 25]

使用 filter

filter 是另一种常见的高阶函数,用于筛选集合中的元素,只保留满足某个条件的元素。

numbers = [1, 2, 3, 4, 5]# 使用 lambda 表达式
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers))  # 输出 [2, 4]# 使用定义的函数
def is_even(x):return x % 2 == 0even_numbers = filter(is_even, numbers)
print(list(even_numbers))  # 输出 [2, 4]

使用 reduce(或 fold

reduce 是一个高阶函数,用于将一个函数应用于一个序列中的元素,以将其缩减为单一的输出值。

from functools import reducenumbers = [1, 2, 3, 4, 5]# 使用 lambda 表达式
total = reduce(lambda x, y: x + y, numbers)
print(total)  # 输出 15# 使用定义的函数
def add(x, y):return x + ytotal = reduce(add, numbers)
print(total)  # 输出 15

使用 list comprehension

列表推导式(List Comprehensions)是一种简洁的语法,用于创建新的列表。

numbers = [1, 2, 3, 4, 5]# 使用 list comprehension
squared = [x**2 for x in numbers]
print(squared)  # 输出 [1, 4, 9, 16, 25]

函数式编程技巧在日常编程中非常实用,通过使用 mapfilterreduce 以及列表推导式等技巧,我们可以更好地处理数据结构和逻辑运算,从而构建更加健壮和高效的程序。这些技巧不仅适用于纯粹的函数式编程语言,也可以很好地融入到混合编程范式中。


从技法到心法:函数式编程的思维模式

函数式编程不仅涉及具体的编程技法,更是一种思维方式。以下是从具体的编程技法过渡到更深层次的心法的一些要点:

技法:具体编程技巧

  1. 高阶函数(Higher-Order Functions)

    • 使用 mapfilterreduce 等高阶函数可以让你的代码更加简洁和易于理解。这些函数可以将复杂操作分解为更小的、可组合的函数。
  2. 不可变性(Immutability)

    • 使用不可变数据结构可以避免状态的意外改变,从而使代码更容易推理和维护。
  3. 递归(Recursion)

    • 递归是一种自然的问题分解方法,可以将复杂问题简化为更小的子问题,直到达到可以直接解决的基本情况。
  4. 模式匹配(Pattern Matching)

    • 模式匹配可以帮助你根据不同情况执行不同的逻辑,特别是在处理代数数据类型时。
  5. 柯里化(Currying)

    • 柯里化可以将多参数函数转换为一系列单参数函数,从而更容易组合和重用。

心法:思维方式

  1. 纯函数(Pure Functions)

    • 心法:培养“无副作用”的思维方式。纯函数的输出仅依赖于输入参数,不依赖外部状态,也不改变外部状态。这种思维方式有助于构建可预测、易于测试的代码。
  2. 数据为中心(Data-Centric Thinking)

    • 心法:将注意力集中在数据流上,而不是控制流。在函数式编程中,数据通过一系列纯函数流动,而不是通过状态的改变。这种思维方式可以让你更专注于数据处理逻辑,而不是控制逻辑。
  3. 函数组合(Function Composition)

    • 心法:将复杂问题分解为更简单的子问题,并通过组合简单的函数来构建复杂的逻辑。这种思维方式鼓励你从整体到局部逐步构建解决方案。
  4. 惰性求值(Lazy Evaluation)

    • 心法:延迟计算,只在需要时才进行计算。这种思维方式有助于提高效率,特别是在处理大量数据时,可以避免不必要的计算。
  5. 抽象化(Abstraction)

    • 心法:将常见模式抽象化为通用的函数或类型。例如,通过高阶函数将常见的操作抽象化为通用的处理流程。这种思维方式有助于提高代码的复用性和可维护性。
  6. 分治法(Divide and Conquer)

    • 心法:将问题分解为更小的子问题,逐步解决。这种思维方式不仅适用于递归,还可以应用于其他问题解决策略,如分批处理、分治算法等。
  7. 函数作为第一类公民(Functions as First-Class Citizens)

    • 心法:将函数视为与其他数据类型同等重要的实体。这种思维方式鼓励你在编程中充分利用函数的能力,将函数作为参数传递,或将函数作为返回值使用。
  8. 并行思维(Parallel Thinking)

    • 心法:函数式编程中的纯函数和不可变性使得代码更容易并行执行。这种思维方式有助于构建可扩展、高性能的应用程序。

实践案例

示例:使用函数式编程思维处理数据流

假设我们需要从一个列表中筛选出所有的偶数,并计算它们的平方和。

传统过程式编程实现

numbers = [1, 2, 3, 4, 5, 6]def process_numbers(nums):even_numbers = []for num in nums:if num % 2 == 0:even_numbers.append(num)squared_sum = sum([num**2 for num in even_numbers])return squared_sumresult = process_numbers(numbers)
print(result)  # 输出 56

函数式编程实现

from functools import reducenumbers = [1, 2, 3, 4, 5, 6]def process_numbers(nums):even_numbers = filter(lambda x: x % 2 == 0, nums)squared_numbers = map(lambda x: x**2, even_numbers)squared_sum = reduce(lambda x, y: x + y, squared_numbers)return squared_sumresult = process_numbers(numbers)
print(result)  # 输出 56

通过掌握函数式编程的思维模式,你可以更自然地运用函数式编程的技法。从具体的编程技巧过渡到更深层次的思维方式,可以帮助你构建更健壮、可维护的代码。函数式编程不仅仅是关于如何编写代码,更是关于如何思考和解决问题。通过培养这些思维方式,你可以更好地应对复杂的编程挑战,并提高代码的整体质量。


总结

函数式编程提供了一种强大的编程范式,通过纯函数、不可变性、高阶函数等核心概念,可以简化代码、提高代码的可读性和可维护性。虽然函数式编程具有一定的学习曲线和性能开销,但在实际开发中结合函数式编程和其他编程范式通常是更灵活的做法。

通过这篇文章,我们了解了函数式编程的基本概念和核心技术,探讨了函数式编程的本质,并通过实际案例展示了如何在日常编程中应用函数式编程技巧。希望本文能够帮助你更好地理解和应用函数式编程,提高编程效率和代码质量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1543711.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习:卷积神经网络CNN

目录 一、什么是卷积&#xff1f; 二、卷积神经网络的组成 1. 卷积层 2. 池化层 3. 激活函数 4. 全连接层 三、卷积神经网络的构造 四、代码实现 1.数据预处理 2.创建卷积神经网络 3.创建训练集和测试集函数 4.创建损失函数和优化器并进行训练 一、什么是卷积&…

LPDDR4芯片学习(一)——基础知识与引脚定义

一、基础知识 01 dram基本存储单元 当需要将一位数据存储到DRAM中时&#xff0c;晶体管会充电或放电电容。充电的电容表示逻辑高&#xff08;1&#xff09;&#xff0c;放电的电容表示逻辑低&#xff08;0&#xff09;。由于电容会随着时间泄漏电荷&#xff0c;因此需要定期刷…

学习记录:js算法(四十三):翻转二叉树

文章目录 翻转二叉树我的思路网上思路递归栈 总结 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点 图一&#xff1a; 图二&#xff1a; 示例 1&#xff1a;&#xff08;如图一&#xff09; 输入&#xff1a;root [4,2,7,1…

Python记录

1.冒泡排序 时间复杂度O&#xff08;n^2) 选择、插入都是 def bubble(data, reverse):for i in range(len(data)-1):for j in range(len(data)-i-1):if data[j] > data[j1]:data[j], data[j1] data[j1], data[j]if reverse:data.reverse()return data 2.快速排序 时间…

护理陪护小程序|陪护系统||陪护系统开发

在当今社会&#xff0c;随着人口老龄化的加剧和家庭结构的变化&#xff0c;护理与陪护服务的需求日益增长。为了更好地满足这一市场需求&#xff0c;并提升服务效率与质量&#xff0c;护理陪护小程序应运而生。这类小程序不仅为用户提供了便捷、高效的服务预约与管理平台&#…

828华为云征文 | 云服务器Flexus X实例,Docker集成搭建Redis集群

828华为云征文 | 云服务器Flexus X实例&#xff0c;Docker集成搭建Redis集群 Redis 集群是一种分布式的 Redis 解决方案&#xff0c;能够在多个节点之间分片存储数据&#xff0c;实现水平扩展和高可用性。与传统的主从架构不同&#xff0c;Redis 集群支持数据自动分片、主节点故…

J Transl Med结肠癌分子分型+简单实验

目录 技术路线 实验设计&#xff08;药物敏感性&#xff09; 亮点 方法 从 TCGA 和 GEO 数据库下载大量和单细胞 RNA 测序以及 CRC 的临床数据。HRGs 和 LMRGs 来自分子特征数据库。使用 R 软件包 DESeq2 进行差异表达分析。使用无监督聚类进行分子亚型。使用单变量 Cox 回…

嘉宾云集旌城 只为大赛而来 2024ISGC国际烈酒(中国)大奖赛在德阳落下帷幕

秋高气爽、古蜀之源&#xff0c;迎来第六届国际烈酒&#xff08;中国&#xff09;大奖赛&#xff1b;五谷丰登、重装之都&#xff0c;齐聚百名国际烈酒大奖赛评委。 9月18日&#xff0c;由德阳市人民政府、国家葡萄酒及白酒露酒产品质量检验检测中心、上海合作组织多功能经贸平…

图片压缩怎么弄?教你5种图片压缩小技巧

现如今&#xff0c;图片已成为我们日常生活和工作不可或缺的一部分。然而&#xff0c;高清图片往往伴随着庞大的文件体积&#xff0c;给存储和传输带来诸多不便。这时候我们就需要对图片进行适当的压缩处理&#xff0c;那么该怎么做呢&#xff1f;下面教大家5种图片压缩小技巧&…

GBase 8s 安装手册

没有失败&#xff0c;只有暂时停止成功&#xff01; 一&#xff1a;简介 GBase 8s 产品支持多种处理器平台&#xff0c;除国际主流的 x86_64 处理器&#xff08;包括 Intel 和 AMD&#xff09; 外&#xff0c;全面支持飞腾、鲲鹏、龙芯、兆芯、海光、申威等国产处理器。 GBas…

2025秋招内推|招联金融

【投递方式】 直接扫下方二维码&#xff0c;使用内推码: igcefb 【招聘岗位】 深圳&#xff0c;武汉&#xff1a; 后台开发 前端开发 数据开发 数据运营 算法开发 技术运维 软件测试 产品策划 产品运营 客户体验管理 风险管理 资产管理 【校招流程】 简历投递&#xff1a;9月…

kafka 消费者线程安全问题详细探讨

内容概要 主要内容 常见错误案例 下面这段代码大概逻辑 初始化时 实例化KafkaConsumer, 开启线程拉取消息并且处理 资源释放回调 停止线程、调用kafkaConsumer.close进行资源释放 表面上没有问题&#xff0c;但实际上可能出现线程安全问题&#xff0c;因为poll 和 close 两…

Jetpack Compose 核心组件(Text, Images, Buttons)(6)

导读大纲 1.1 基本组件介绍1.2 Text1.2.1 基本用法1.2.2 设计文字风格 1.3 Image组件1.3.1 从各种来源加载图片1.3.2 关键属性1.3.3 如何加载和显示不同类型的图像1.3.4 内容描述和无障碍访问: 1.4 Button组件1.4.1 基本用法1.4.2 装饰和自定义1.4.3 处理按钮点击1.4.4 重要考虑…

基于python深度学习遥感影像地物分类与目标识别、分割实践技术

我国高分辨率对地观测系统重大专项已全面启动&#xff0c;高空间、高光谱、高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成&#xff0c;将成为保障国家安全的基础性和战略性资源。未来10年全球每天获取的观测数据将超过10PB&#xff0c;遥感大数据时…

JS惰性函数两种实现方式

惰性函数的本质就是函数重写&#xff0c;所谓惰性载入&#xff0c;指函数执行的分支只会发生一次。那什么时函数重写呢&#xff1f;由于一个函数可以返回另一个函数&#xff0c;因此可以用新的函数在覆盖旧的函数。 惰性函数有两种实现方式&#xff1a; 1、在函数被调用时&am…

案例研究丨国控星鲨利用DataEase释放数据潜能,重塑业务视野

国药控股星鲨制药&#xff08;厦门&#xff09;有限公司&#xff08;以下简称为国控星鲨&#xff09;始创于1952年&#xff0c;前身为厦门鱼肝油厂&#xff0c;距今已经有70余年历史&#xff0c;是国家商务部认定的“中华老字号”企业。2011年&#xff0c;国药控股与厦门轻工集…

2024年国庆小长假即将来临,陪猫咪的同时应该如何清浮毛

在父母眼中我们是不是永远都长不大&#xff1f;每次和他们讨论一点事情就开始吵起来。这不&#xff0c;前两天想着和好久不见的朋友去见面&#xff0c;出门前还要被逼问一番。 去到朋友家&#xff0c;发现朋友养了两只可爱的小猫&#xff0c;一时心动上头&#xff0c;我也转身…

通信工程学习:什么是MANO管理编排

MANO&#xff1a;管理编排 MANO&#xff1a;Management and Network Orchestration&#xff08;管理和网络编排&#xff09;在网络功能虚拟化&#xff08;NFV&#xff09;架构中扮演着至关重要的角色。MANO是一个由多个功能实体组合而成的层次&#xff0c;这些功能实体负责管理…

地图定位流程

用户端在小程序认证通过后会自动进行定位&#xff0c;也可以在首页手动定位&#xff0c;定位成功后用户在查询家政服务项目时会根据定位的城市查询该城市有哪些服务项目。 高德地图配置 小程序端的定位是通过手机的定位模块进行定位&#xff0c;定位成功获取经纬度坐标&#x…

吸烟行为检测、重点区域吸烟检测、吸烟检测算法样本标注

吸烟检测算法主要用于公共场所、工作场所和家庭环境中的吸烟行为监控&#xff0c;通过图像识别技术来检测和识别吸烟行为&#xff0c;以确保环境卫生和公共安全。这种技术可以帮助管理者实时监控吸烟行为&#xff0c;及时采取措施&#xff0c;减少二手烟的危害。 一、技术实现…