Tag: 函数式编程

Swift 4.2 Reduce和CoreLocation:总行驶距离🚗

在最近的一个项目中,我遇到了一个非常确定的问题,我敢肯定其他许多开发人员也会遇到:计算列表中存储的位置之间的总距离。 例如,假设您在由CLLocation对象列表表示的地图上有一条自定义路线。 您如何仅从CLLocation对象计算路线的总长度? 其背后的数学很简单,绝对没有理由写一个故事: 总距离等于列表中所有连接的位置对之间的距离之和 。 对于位置[A,B,C,D]的列表,可以表示为: | AD | = | AB | + | BC | + | CD |。 但是,可以使用我们位置对象上提供的函数distance(from :)以不同的方式完成该实现。 样板解决方案: 使用传统的面向对象方法,可以通过几个变量和位置迭代来解决此问题: 样板解决方案 该实现完全按照我们的预期工作,并且对于任何初看它的开发人员来说都是可读性和可理解性。 但是(没有双行中断),对于需要参考下一个/上一个元素以及将在集合迭代期间进行调整的变量的任何给定问题,最有可能重写这9行代码因此命名为样板解决方案)。 递归解决方案: 递归专家将很快意识到这是一个递归问题:我们为递归列表的一部分积累一个临时结果,并使用积累的结果对列表的其余部分执行相同的操作。 这就是为什么递归函数可以帮助我们节省几行样板代码的原因: 递归解决方案 但是仅通过查看递归函数就可以肯定地说,我们获得的一行代码(与样板解决方案相比)不值得在递归调用中引入一致性和简单性的损失-请记住,并非所有开发人员对递归同样感到高兴。 简化的解决方案: 如果我告诉过您所有的样板代码和递归代码都可以限制为一行代码怎么办? 一个纯粹的面向对象的开发人员可能不会相信我,但是实际上,这是可以实现的。 如果考虑我们在做什么,我们将在递归数据结构上应用组合函数(distance(from :)),并以递归方式使用函数的每次应用结果。 这正是函数编程中高阶函数折叠所做的定义¹。 幸运的是,在Swift中,我们有一个类似的功能可以折叠: reduce(_:_:)函数reduce(_:_:) 。 reduce函数将初始结果和闭包作为参数,然后在返回最终结果之前使用闭包组合Sequence的每个元素。 最简单的示例是使用reduce函数对整数列表求和: [2,5,3,10] .reduce(0,+)//返回20 但是,在我们的情况下,我们需要更加具体,因为+函数实际上不适用于CLLocation对象。 相反,我们希望应用distance(from:)函数。 为此,我们还需要引用列表中的上一个(或下一个)元素。 reduce函数不会自动为您提供下一个元素的访问权限(与其他任何迭代一样),因此,为了解决此问题,我们可以使用元组作为初始累加结果,第一个元素是累加距离,第二个元素是累加距离先前的CLLocation对象: (CLLocationDistance, CLLocation?) 。 location元素是可选的,因为在我们提供给reduce函数的初始结果中没有先前的元素。 […]

如何:在Swift中映射,缩小和过滤

由Reinder de Vries撰写于2017年5月3日在App Development中 Swift的编程功能Map,Reduce和Filter可能难以挑战。 特别是,如果您总是编写for循环来解决迭代问题! Map,Reduce和Filter函数来自函数编程领域。 在Swift中,您可以使用Map,Reduce和Filter遍历诸如Array和Dictionary集合类型,而无需使用for循环。 在构建应用程序时,通常使用过程式或面向对象的编程方式。 函数式编程是不同的:它仅处理函数。 没有变量,没有“状态”,没有for循环-只是函数。 Swift编程语言非常适合于函数式编程。 但是,您无需严格地编写功能代码,只需采用功能编程中的概念(例如Map,Reduce和Filter)即可帮助您学习如何更好地编写代码。 Map,Reduce和Filter通常被称为高阶函数 ,因为这些函数将一个函数(一个闭包)作为输入,而将返回函数作为输出。 严格来说,Swift将在使用高阶函数时返回操作(即映射数组)的结果,而“纯”函数语言将返回函数的集合。 如果您在想:“伙计,我不需要功能编程或数据处理,因为我的应用程序不需要这样做!” —不要在这里停下来。 在最近的应用程序项目中,我多次使用过Map,Reduce和Filter: 过滤成本/收入值,使其达到一定阈值,然后再将其包含在折线图中 将成千上万的电影评分降低为一个平均评分 在此Photo App模板中的标签上映射一些操作(小写,删除“#”) 您当然可以通过for循环解决所有这些问题,但是您会发现使用map,reduce和filter函数可以使代码更简洁,可读性和性能更高。 在本指南中,您将学习如何使用地图,缩小和过滤功能。 您将对集合类型 (如Array执行这些功能。 以下是简要概述: map函数遍历集合中的每个项目,并对集合中的每个元素执行操作 reduce函数循环遍历集合中的每个项目,并将它们组合为一个值 filter函数遍历集合中的每个项目,并返回仅包含满足包含条件的项目的集合 换句话说: map功能将功能应用于集合中的每个项目。 考虑将一组值“映射”到另一组值。 reduce函数将一个集合变成一个值。 可以认为它实际上是将多个值减少为一个值。 filter函数仅返回通过if -statement条件且仅当该条件导致true的值的数组。 有趣的事实: MapReduce是基本的大数据处理概念,其中对集合并行执行密集操作。 一个示例是将一本书的页面概括为一个单词(映射),然后将这些单词存储在字母框中(减少)。 跳至相关章节: 使用地图功能 使用减少功能 使用过滤功能 链接图,缩小和过滤 结论 准备? 我们走吧! 成为专业的iOS开发人员 开始使用iOS 12和Swift 4 注册我们的iOS开发课程“ 零到App […]

Swift 4 ~~高阶函数-过滤,映射,归约和排序

您可能已经听说过Swift中的高阶函数 。 简单来说,高阶函数是开发人员友好的代码段,可在几行内完成复杂的计算。 很快我们有了Filter() , Map() , Reduce()和Sorted() HOF。 所有这些都有其自身的优点,并且在我们的代码中易于使用。 让我通过Swift4中的一些有趣的示例向您展示如何使用它们。 1.过滤器(_ 🙂 Filter方法将检查条件,如果条件满足,它将返回一个对象。 您可以将filter(_ 🙂与String,Array,Dictionary,Set等一起使用。 让我们在Set上看看如何使用它。 我有一组名称,我需要选择只有5个字符的名称。 那我该怎么办呢? //名称集 let nameSet:Set = [“ trivan”,“ mary”,“ larns”,“ tria”] //结果集 var resultSet:Set = [] //遍历nameSet中的每个元素 nameSet.forEach {(元素)在 如果element.count == 5 { resultSet.insert(element) } } print(resultSet) 如何使用HOF 过滤器(_ 🙂完成此操作? 让我用过滤器(_ 🙂向您展示上述要求的代码 let nameSet:Set = [“ trivan”,“ mary”,“ […]

Swift中的In-Out参数

嗨,我将向您介绍Swift中的In-Out参数。 什么是输入输出参数? 我们为什么要使用它? 我们想在哪里使用它? 阅读本文以清除您的问题。 问题1:什么是输入输出参数? 如果我们阅读了Apple的官方文件,我们可以看到它说: 为了简单起见,可以这样说: inout 表示修改局部变量也将修改传入的参数。 没有它,传入的参数将保持相同的值。 以使用In-Out参数为例: 以下功能有助于交换值。 a的值存储到临时变量A中。 b的值分配给a。 然后赋给临时A的值 到b。 问题2:如果在上述示例中将inout替换为var怎么办? print(firstNumber)将打印6 。 和 print(secondNumber)将打印7 。 下面的视频将帮助您了解In-Out参数的工作原理。 祝您阅读愉快!!!!……再见🙂

Monads —示例和定义

例子 我们Swift程序员联系并使用了一些monad,甚至不知道它们是这样分类的:数组(以及所有其他Sequence)和Optionals都是此语句的有效示例。 还有一些框架可以实现其他monad:RxSwift,一种反应式编程框架,可以实现与这些主题相同的主题(可以同时观察和观察的对象)。 它们在纯函数式语言中甚至更有用,以便专门处理可控的副作用。 克里斯·史密斯(Chris Smith)在这篇文章中描述了其中的四个非常重要的部分,即“ Catapocalypse的四个骑士”: 故障 -由于内存不足,无效的人工输入,网络中断等原因,功能可能导致错误; 依赖 -从一个函数调用到下一个函数调用,作为有状态操作; 不确定性 -来自相同参数的不同结果; 破坏 -对世界有永久影响的行动,例如I / O。 我们可以用这些语言找到其他单子,以控制状态,记录(作家单子),IO和其他效果。 当考虑这些示例时,将单子作为容器/盒子的比喻变得更难以适应。 我认为它带来了一个隐式的结构概念,该结构很好地包含了Arrays和Optionals,但是需要扩展和重新研究才能容纳其他结构。 从我看来,看这些例子并从中开始似乎使学习者难以建立单子概念(甚至是目的)。 另一方面,理解其主要用法之一非常重要:定义一种以统一和可控的方式处理其他计算和副作用的通用方法。 目的 在跳到定义和概念之前,我认为重要的一点是,在函数式编程中使用monad的目的是允许将具有返回值类型的函数组成为另一个将不同类型作为参数的函数。 尽管如此,它并非旨在使每个返回值都与任何参数类型匹配:monads处理某个函数返回的某些泛型类型,以将它们与期望其关联类型作为参数的函数组成(例如:连接一个由返回的Array 一个需要整数的函数,例如f(Int )。 Monad具有多种用途,但它们的通用目的(至少从编程的角度而言)是连接事物。 定义 由于示例仅部分支持概念理解,因此让我们转到另一种方法:从定义的角度出发。 编程语言上的Monad是通用类型(例如:Array ),这意味着它与任何T类型(例如Int , String等)或至少与具有某些约束的一组类型(例如Dictionary )相关联键值对:它们可以将任何类型都保存为值,但是键被限制为符合Hashable协议的类型。 除了是通用类型之外,monad还应该实现两个功能: 单位函数 -用于monad类型M的类型构造 函数 ,该类型构造 函数从关联的类型a接收值并将其转换为具有最小上下文M(a)的泛型类型-“处于最小上下文中”的含义取决于类型本身。 对于一个数组,接收到一个值,如整数1 ,它应该创建一个只有一个元素[1]的整数数组; (可选),接收字符串“ Hello!” 应该创建一个Optional ,其值为.some(“ Hello!”) 。 这可以扩展到任何其他monad类型。 平面映射函数 -此函数是为具有关联类型a的monad M的每个实例实现的高阶函数(意味着:它接收另一个函数作为参数) 。 它接收作为参数的函数,该函数将类型a的值转换为相同类型M的另一个monad,但可以具有另一个关联类型b […]

是可选的,闭包可以抛出,是的。 –本–中

是可选的,闭包可以抛出,是的。 但是,没有语言功能可用于处理回调中的错误。 让我解释: 想象一下,我将闭包传递给了进行网络调用的函数。 如果该网络调用失败(例如,我收到HTTP 503 ),此功能将如何告诉我? 我看到三种方式: 回调有两个参数:成功值和错误值,两者都是可选的。 如果成功,则错误为nil ;如果错误,则成功为nil 。 这是不理想的,因为两者都可能为nil或都不为nil ,在这种情况下这是无意义的 该函数接受两个回调:一个在成功时传递值,一个在失败时传递错误值。 这样比较好,但是仍然可以同时调用两者,这是胡说八道。 另外,它体积大,并且没有利用Swift的闭包语言功能,例如在仅需要1个闭包的函数上省略括号。 回调采用一个参数,该参数是非可选的Result类型。 这是理想的,因为它永远不会同时具有成功或失败状态。 此外,您可以利用语言功能,例如省略括号和模式匹配。 同意,到今天为止,它体积很大。 但是,我看到了将来可以简化的一种方式,尤其是在标准库中提供了Result时。

迅速。 功能可选。 第1部分

Optional是Swift中的基本类型。 尽管几乎无处不在,但大多数开发人员并未充分利用它,甚至没有以错误的方式使用它。 可选绑定反对DRY原理,并引入了不必要的条件。 在这个由多部分组成的系列文章中,我们将讨论Optional真正含义,如何正确使用它并应用一些高级知识,以便为Optional计算创建方便的功能性eDSL。 其他重要主题包括Swift中的依赖项注入策略,错误处理,隐式展开的Optionals和类型强制转换。 虽然不能总是避免使用最后两个,尤其是在与Objective-C代码交互时,但它们都是纯Swift的代码味道。 由于本系列的主要目的是理解功能概念以及如何在Swift中应用它们 ,因此我们将讨论和绘制而不是代码。 您会看到,还有很多工作要做。 第一部分从Optional 。 然后我们将讨论可选绑定 。 我们的旅程将把我们引向基本的功能概念: 纯功能 。 在那里,我们将停下来,探索更多内容,直到下一部分。 为什么可选? 在Objective-C中没有“ Optional这样的类型。 相反,如果函数或属性不返回值,则返回nil 空的 NSObject指针。 可以安全地将消息发送到nil并将其作为参数传递。 但是Swift没有像Objective-C这样的指针。 此外,如果任何类型可以为nil ,我们的程序如何保证类型安全? 如果我们传递nil字符串而不是数字,编译器如何弄清楚怎么办? 如果我们将nil传递给无法处理的函数怎么办? 为了处理此问题,引入了Optional 。 有什么可选的? 让我们看一下Optional声明: 枚举可选 { ///没有值 无案 ///值的存在 案例一些(包装) … } 因此,我们看到的第一件事告诉我们Optional是容器类型 :它封装了一个值。 图片 1.简单显示一个可选的Int值容器。 这里的黄色圆圈表示普通类型,而蓝色正方形表示“可选”容器。 您会看到, .none没有任何类型约束,因此使用诸如nil这样的文字很方便。 一个空盒子只是一个盒子,没有什么有趣的。 Optional还可以保护您避免将nil值传递给无法处理它们的函数。 这就是可选绑定起作用的地方。 可选绑定 可选绑定是用于访问包装到Optional的值的语句。 它看起来比声音更好,并且具有熟悉的语法。 如果您已经尝试过一些Swift,您将不会感到害怕 […]

Swift中用于像我这样的傻瓜的功能组合-第3部分

如您所见, Array每个值都由传递给map的函数转换。 我经常看到的一个错误是,认为 map 是用于集合的操作 。 它对于集合当然是有用的,但是将地图视为对集合进行操作的一种方式将您限制为集合类型。 在Swift中,Swift标准库中有一些针对Optional和Result类型的map函数,一旦您开始认识到它们在哪里有用,就可以为系统中定义的许多其他类型定义map 。 Optional和Result都不是集合,并且它们都是可map 。 两者还具有无法映射的状态。 当Optional为nil ,由于没有值,它无法将提供的转换函数应用到map函数,因此map跳过执行转换函数,而Optional值保持为nil 。 这种行为非常类似于Swift可选绑定的工作原理,但是没有所有样板。 首先,使用可选绑定而不是map的示例: 接下来,是一个使用Optional的map实现来完成相同任务的示例。 最后,一个使用“可选”的“ map”实现的示例显示,当“可选”为nil时,跳过了转换。 以类似的方式,新的Swift 5 Result类型中包装的值如果为.failure ,则无法进行转换,因此将跳过转换函数,并且一系列操作的结果将为.failure 。 这在组成一系列动作时非常有用,在这些动作中,您仅希望在前面的步骤成功后才执行该动作。 我将回到这一点,并在本文中进一步扩展。 以下是一些片段,展示了map如何在Result类型上工作: 所有这些的最终结果是,您可以将依赖于先前操作结果的操作链接在一起,而无需使用嵌套的ifs。 map函数将正确调用或跳过转换。 但是,这些示例中潜伏着一个问题。 如果Optional map中的转换函数产生另一个Optional ,则结果为Optional<Optional> ,即嵌套的Optional 。 完全有效,但很难处理。 在以下示例中查看有效内容的类型: 有一种避免这种嵌套的解决方案,在Swift(和其他(但不是全部)功能语言)中称为flatMap 。 Monad简介—认为可映射和可平面映射 和以前一样,请随时在线搜索Monad的完整定义。 范畴论的定义很难解析。 为了便于讨论,您需要知道的是Monad是包装类型,它具有flatMap函数和map函数。 flatMap函数将特定类型的转换函数(或态射)作为参数,并将该转换应用于包装的一个或多个值。 特定的转换是一种输入类型与包装类型相同且输出类型与Monad本身相同但包装一个转换值的转换。 换句话说,形状为(A) -> M ,其中M表示为FlatMapped的Monad类型。 换句话说, Optional上的flatMap期望形状为(A) -> Optional的转换函数, Result上的flatMap期望形状为(A) […]

迅速移动!

这有点哲学性,所以请忍受我。 我一直认为没有正确的时间去错! 但是我想我错了,显然错误的正确时机是当您知道自己是可以改变它的时候。 为了更加了解我的情况,我接受了迅速的采访,我几乎不了解函数式编程。 我想知道为什么它与Obj C有如此大的区别,但是当我偶然发现函数式编程时,我知道了原因! 我确信从C到C ++时,某些ppl有相同的经验(几十年前)。 用不同的范式思考就像是观念的转变。 就像那些拼图,您改变了视角,然后拼图看上去就完全不同了。 Swift是真正的现代编程语言。 因此,最好地理解它最好理解其设计中已包含的基本思想。 swift背后的基本思想之一是迈克尔·费瑟斯(Michael Feathers)的这则推特最恰当的描述,该推特谈到了函数式编程与面向对象编程 “ OO通过封装活动部件使代码易于理解,FP通过减少活动部件使代码易于理解。” Swift通过添加枚举和结构之类的值类型数据结构来减少活动部件,如果不能将一个对象简单地传递给一堆函数(将其变异),则更容易发现问题出在哪里,理论如下如果语言公开较少的潜在易错功能,则开发人员更不可能犯错误。 在初步了解之后,我回到了功能范式的基础,然后将重新学习更深入的知识,并计划在接下来的几周中记录自己的经验。 我希望这对于从Obj C到迅速发展的任何人都是有用的指南!

在Swift中链接异步函数

在本文中,我们将看到如何在Swift中使用函数组合来链接多个异步请求(不必用于RxSwift)。 编辑:Brandon Kase指出,这种组合实际上称为Kleisli组合,并且要使用的正确运算符是fish / Kleisli运算符: >=> (而不是|> )。 这很棒! 一件事:我建议使用> =>运算符代替|>,因为|>(称为管道转发)传统上用于向后函数应用程序。 您在这里拥有的是kleisli合成(并且> =>是kleisli合成运算符)。 -Brandon Kase(@bkase_) 2018年2月1日 [您可以下载本文的配套 Playground 。] 假设我们有一个具有以下模型的付款验证应用程序: 对Web服务的一般请求可能如下所示: 正如您应该猜到的那样,我们将使用函数组合来实现这一点。 让我们采用通用请求函数: func fetch(_输入:InputType,完成:(Result )->无效) 并用以下别名表示它: 公共类型别名Request =(T,@转义RequestCompletion )->无效 在我们的例子中,U将映射到 Result 。 接下来,我们将定义一个运算符,该运算符将允许我们通过管道传递请求。 分解> =>运算符 该运算符是T , U和V三种类型的泛型运算符,并使用2个函数f和g作为参数,其中: f取一个T并以Result g取一个U并以Result 。 它返回一个带有签名的组合函数: Request<T, Result>即接受f输入并以Result完成的函数。 注意: 输入为 T 类型 CombineCompletion的类型为RequestCompletion RequestCompletion<Result> 。 这个返回函数的实现从应用f开始,然后在f的完成块中,它切换一个Result 。 如果f以.success […]