Tag: 函数式编程

转换运算符:地图,flatMap和flatMapLatest

RxSwift提供了一系列运算符,它们可以极大地控制您要如何处理应用程序中的数据和事件。 当您要对来自序列的数据进行建模以适合您的需求时,可以使用转换运算符。 换句话说,准备数据以符合订户的要求。 例如,要转换从Observable序列发出的元素,可以使用map运算符; 当元素从源Observable序列发出时,map将对其进行变换。 这类似于标准Swift库中的map(_ 🙂方法,不同之处在于此地图可用于Observable序列元素。 地图运算符的大理石图表示将如下所示: 实际地图(_ 🙂 我们将举一个在操场上使用地图的例子。 我们将需要我们的辅助函数,即executeProcedure(with description:String,procedure:()-> Void) 。 此函数有两个参数:字符串描述和过程闭包。 然后打印说明,然后执行该过程。 公共函数executeProcedure(用于描述:字符串,过程:()->无效){ print(“执行程序:”,描述) 程序() } 现在,我们将使用of运算符创建一个Observable整数序列: executeProcedure(for:“ map”){ Observable.of(10,20,30) } 然后,我们将使用map运算符将每个整数元素自身相乘: Observable.of(10,20,30) .map {$ 0 * $ 0} 然后,我们将订阅onNext来打印每个转换后的元素: Observable.of(10,20,30) .map {$ 0 * $ 0} .subscribe(onNext:{ 打印($ 0) }) 之后,我们对subscribe(onNext 🙂的返回值调用dispose() 。 请记住,订阅将返回Disposable 。 该函数的总体代码如下: executeProcedure(for:“ map”){ Observable.of(10,20,30) […]

在Swift中通过委托传递数据

我想写一篇直截了当的文章。 直截了当,这样我们就可以看一下本文并知道如何在我们自己的项目中使用委托设计模式来传递数据。 我们走吧。 前提条件 强烈建议您首先阅读有关协议的信息。 您不必这样做,但这可能有助于巩固您的理解。 Swift 3中的协议简介 何时 我要说的是什么时候我们想通过委托传递数据。 考虑一下prepareForSegue,然后考虑相反的方向。 如果prepareForSegue指向前方,则委派指向后方。 假设prepareForSegue是从VCInitial到VCFnitial,则委派将是从VCFinal到VCInitial。 这是我们想要使用委托传递数据的时候。 这也是我们马上要做的事情! 设定 打开一个新的Xcode项目,然后随意调用它。 创建两个视图控制器。 将第一个命名为VCInitial,第二个命名为VCFinal。 应该看起来像: 现在将VCInitial嵌入导航控制器。 这样,我们在VCFinal上具有后退按钮。 嵌入后,应如下所示: 大。 现在让我们在VCInitial和VCFinal之间创建一个VCFinal 。 调用segue VCInitialToVCFinal 。 现在在我们的VCInitial 。 我们想使用我们的标识符执行segue。 因此,创建一个按钮并将其连接到IBAction 。 调用IBAction函数btnPerformSeguePressed 。 看起来像: 然后在我们的IBAction内部,使用我们的标识符执行segue。 performSegue(withIdentifier:“ VCInitialToVCFinal”,发送者:nil) 现在为VCFinal创建一个按钮,并将其连接到IBAction 。 称之为btnPassDataPressed 。 半场演出 好的,欢迎收看半场比赛。 我们将回顾当晚的亮点。 好第一件事。 两个View Controller和两个按钮。 关系。 好了,这是半场表演的结尾。 我们现在正在转向协议。 实施委派 仍在VCFinal.swift […]

另一个Monad教程

适用于Swift程序员 介绍 函子和monad是一个概念,每个开始学习函数式编程的人迟早都会联系起来,并且通常很难与之抗争。 Monad是一个简单的概念:它具有简洁明了的定义。 另一方面,此定义基于多个抽象层,这使它很难掌握。 我们可以认为monad是简单的(与复杂相反),但是对于大多数人而言,学习monad通常很困难(与easy相反)。 要了解其完整的应用和通用性,这是最困难的事情之一。 这可能是一个解释,为什么周围会有无数的monad教程。 在建立了处理这些抽象的思维模型并获得对概念本身的良好理解之后,通常人们会尝试使过程对于新手来说更加可口,从而使编写教程几乎成为通俗的“通过仪式”。 我认为这与我没什么不同,所以我们继续。 在接下来的系列文章中,我的重点是就我在此过程中发现的陷阱进行思考。 我希望它将使本教程至少与以下术语中已有的一些教程有所不同: 我将尝试使本教程尽可能地实用,探索概念,但尝试将其付诸实践(理解为:代码)。 把它带入这个领域,对我们作为程序员来说更清楚,这对我有所帮助,我也希望可以对其他人有所帮助。 几种有关monad的解释试图使用隐喻来使其变得不太抽象。 在这些隐喻上,单子表示为设计图案,容器或盒子,卷饼,鸭带或“可编程分号”。 尽管它们都可以为单声道模型建模,但是有很多概念和抽象不适合或需要某种调整才能保持。 这就是为什么詹姆斯·伊里(James Iry)说单子像大象(使用盲人和大象的寓言)的原因:您可以有一些直觉或理解概念的某些部分,但仅看到细节会使您错过整个画面。 不知何故,我同意布伦特·约基(Brent Yorgey)的观点,即试图将这一概念适合于隐喻是一种谬论,因为它最大程度地减少了与抽象的斗争是理解过程的一部分。 因此,我将尝试着重于概念而不是隐喻,但我将尝试使用它们指出我在学习过程中与该隐喻有关的一些陷阱(我认为这些观点使我更难理解。概括这个概念)。 根据概念和示例,本教程分为多个小帖子。 我希望它使跟踪和跳过已知部分变得容易。 绝大多数monad教程都使用Haskell进行举例说明。 Haskell是一种纯函数式语言,其语法与大多数程序员习惯使用的命令式和OO语言截然不同。 因此,尝试阅读它们会带来两个挑战,而不是一个挑战:理解概念和语言本身。 找到这个Scala教程对我的学习至关重要。 Scala是一种多范式语言,尽管具有强大的构造,但比Haskell更易于阅读(至少对我而言)。 在本教程中,我将使用Swift,也是一种多范式语言,但我认为它也可以轻松转换为其他多范式语言。 我需要带些什么? 我将重点介绍monad概念及其理解的基石。 有一些以前的知识,我不会关注,但是非常重要: Swift-代码示例是使用Swift语言编写的,因此尽管我认为可以轻松地将其映射到其他编程语言(例如C#,Java,Kotlin等),但是该语言的知识非常重要。 泛型 -泛型类型是monad的基础。 理解概念及其语法很重要,以便理解本教程中的示例和代码。 函数式编程 — Monad是与函数式编程范例相关联的构造,因此了解它以了解monad的用途及其用法很重要。 本教程有两个基本概念:函数组成和函数是函数编程中的“一等公民”(它们是类型,它们就像任何其他类型一样,可以将它们归为变量,并将其作为参数传递到另一个函数或作为函数调用的结果返回)。 所有这些都说明了这一点,并希望我至少可以部分摆脱“ monad诅咒”(当某人终于能够理解它时,他无法向任何其他人解释它),让我们从这里开始。 如果您想转至特定职位,则以下是所有与monad相关的帖子的列表。

Swift — memoize()逐步

最近,我一直在阅读有关Swift 3未来的文章。 对在服务器上使用Swift以及在该方面完成的工作特别感兴趣。 迅捷轨迹🚀 Swift具有巨大的潜力,可以成为构建从VR到移动到服务器再到AI 的主流语言。 仍然缺少一些关键的构建块,但已经奠定了坚实的基础。 其中,可以说是最重要的功能支持 ,从第一天开始就随语言一起提供。 功能迅捷 语言结构很好地表达了功能支持,这使得一些疯狂的热门功能实现成为一个例子,其中一个示例就是在WWDC’14 Session 404 – Advanced Swift中引入的备忘录功能(讨论从00:38开始)。 在这篇文章中,我希望探讨memoize的性质并解释其工作原理,将其从WWDC’17的“高级”轨道移至“基本”轨道。 记住 乍一看, memoize’s实现看起来像Brainfuck启发的Hello World,但请放心-它是Swift。 纯功能性Swift😼 步骤2:递归记忆 为什么此版本的memoize是递归的要点是,将工作闭包作为参数传递给它自己 ,这使工作闭包可以对自身的memoize’d版本进行递归调用。 这有资格获得令人赞叹的史诗般的胜利🎆 14号线 使用尾随闭包语法,我传递了2参数工作闭包以进行memoize. memoize的结果(环绕式闭合)存储在名为factorial的参数中。 从工作闭包体内 对 factorial(x-1) 的调用 是指传递给闭包的参数,它与 let factorial 命名 完全无关 。 15号线 let factorial类型为(Int) -> Int 推断输入Int是因为发现Int Type符合以下要求: 1.符合Hashable协议。 2.支持== , *和—操作。 之所以推断Return Int是因为在返回之前没有执行任何类型转换。 1号线 memoize的递归支持版本还使用2个类型占位符: T, […]

降低

过滤,缩小和映射: 轻按一下即可转换收藏。 这些功能上的朋友, 您将清除的代码, 输入不可变,没有陷阱。 映射和过滤器引起了很多关注,但是我说减少是重要的一环。 或者,如果您对效率感兴趣,该怎么做:您可以使用reduce来构建地图和过滤器。 如果您只想学习一种,请选择减少。 功能朋友 Map具有对序列中的每个项目执行某些操作并收集结果的有用行为。 let words = [“hello”, “there”] let shoutyWords = words.map { $0.uppercased() } // [“HELLO”, “THERE”] map的输入是大小为n的序列,输出的大小也为n 。 接下来,使用过滤器可以确定序列中要保留(和丢弃)的项目。 let numbers = 0…10 let evenNumbers = numbers.filter { $0 % 2 == 0 } // [0, 2, 4, 6, 8, 10] 输出大小将介于0到n之间,具体取决于要过滤的事物数量。 减少什么? 减少减少 像其他两个操作一样, reduce接受一个序列作为输入,但是它的输出更为通用:它可以是您想要的任何东西! […]

在Swift中减少– Khoa Nguyen –中

减少Swift 版本:Swift 3 您可以使用reduce组合集合中的所有项目(Array或Dictionary)以创建一个新值。 让我们看一下带有两个参数的reduce方法:initialResult和Combine闭包。 这是我们使用这种方法的方式: 如果您觉得很难记住,请使用以下解决方案: 它也适用于简短版本: 当我们使用循环而不是reduce: 您将看到使用函数式编程(在这种情况下,使用reduce )带来的更复杂的问题。 问题 :我有一个Product数组,每个元素都有3个属性:名称,价格,availableAmount。 我如何计算总价格和总可用量与reduce这个数组的所有元素? 在这种情况下,我使用Tuple作为初始值和返回类型 结果: 提示:如果您发现难以理解使用Tuple,进行reduce Tuple,回顾这张图片。 您可以使用循环重写此逻辑,并查看有多少行代码。 我并不是说您用更少的代码会看起来更加专业。 但事实是,您将提高工作效率并节省大量时间。 你喜欢这篇文章? 请分享! 懒输入代码-> Github上的Swift教程

小片段#1:在Swift 3中分组

Swift 3中经典的“分组依据”功能的简短实现,作为数组扩展。 给定一个元素数组和一个条件函数,grouped(by :)使用条件函数返回的键将该数组转换为字典。 条件函数接受一个Element并返回其分类。 例如,如果您要将偶数和奇数分开,则条件闭包将返回“偶数”或“奇数”。 我经常用它来按创建日期分隔元素。 我希望这能帮到您。 如果您知道这样做的更好方法,请在下面的评论中告诉我! 谢谢! 🙌

映射,过滤,减少,拖放Swift。 简单的高阶函数。

我已经对本文的主题进行了很多思考,并想向您介绍一些有用的且经常使用的简单高阶函数。 今天,我想整理一切,即使初学者也可以理解。 高阶函数对我来说很有趣,我将在这四个方面停下来:过滤,映射,缩小,删除。 当然,有4个以上,但是这些是最基本,最有趣的。 过滤器将此类元素返回给您的数组,并通过某个过滤器。 现在,我将向您展示过滤器如何在原始示例上工作: 传统方式 在emptyArray中,我们将具有以下数字:1、3、5、7、9。 代替这么长的代码,让我们使用filter : 结果,我们得到的答案是相同的,但是我们没有将空对象变成大量,也没有摆脱代码堆。 对数组中的每个元素执行操作以构建另一个数组。 想象一下,首先我们有很多成果: 现在让我们再创建一个由这些水果组成的数组。 传统方式 如果要使用map,我们将提供以下代码: 在此示例中,我们创建了一个名为fruitLowercase的空数组,该数组保留字符串值,并将simpleFruits的每个元素添加到fruitLowercase。 我向您展示了地图上最好和最短的版本,如果您想了解更多有关地图的信息,可以这样做,并将其留在下面的评论中。 过滤器帮助我们合并数组中的所有值并获得单个结果。 假设我们有一个任务要计算该数组中的所有字母。 这是一种传统方式: 传统方式 让我们看看,如果使用reduce将会怎样: 通过使用reduce将4行变成1。 0表示我们将开始增加多少。 当condition返回true时,从数组中抛出元素,返回false时停止。 之前: 传统方式 后: 它比以前容易得多。 好了,仅此而已! 我真的希望您能在项目中使用它,并使您的雇主惊奇。 今天,我向您展示了3种不同的高阶函数。 它们可以缩短您的代码并提高其可读性。 在评论中写下您希望我添加的内容,或在下一篇文章中写下。

复合数据源对象和功能方法要素

一旦我(好的,实际上是队友)面临着一项任务, UICollectionView另一个类型的单元格的UICollectionView添加一个单元格。 此外,仅在特殊情况下才显示该额外的单元格,这种情况发生在外部并且不直接依赖于UICollectionView 。 实施的解决方案催生了需要的if – else语句(如果内存UICollectionViewDelegate话)在UICollectionViewDataSource和UICollectionViewDelegate方法中,并且这些语句在生产代码中“安全地”存在了UICollectionViewDataSource UICollectionViewDelegate 。 在任务中,无需考虑更优雅的解决方案,就可以浪费时间和精力。 但是,我一直牢记这个故事,并沉思着一个可以由任意数量的其他数据源组成的数据源实现。 一个显然必须被概括,适合任何数量的原始数据源(包括零和一),并且必须与特定类型无关。 事实证明,它不仅可行,而且也不太复杂(尽管使代码看起来更漂亮有点棘手)。 我想使用UITableView的示例来分享我的先驱。 如果需要,必须容易实现类似的UICollectionView代码。 原始文章是用俄语撰写的,并在此处发表。 “观念永远比客观化更重要” 这是 Alan Moore ( 守望者 , V代表仇杀 联盟,非凡绅士联盟 )的报价(perharps incurate),但是作为程序员,我们真的很在意特定的实现,对吧? 我方法的主要概念是存储UITableViewDateSource对象的数组,返回其节的总数,并可以确定哪个原始数据源负责处理调用。 UITableViewDataSource协议已经具有获取节数,行数等所有必要的方法,但是不幸的是,由于特定的UITableView实例作为方法参数,我发现将它们用于我的目的非常尴尬。 这就是为什么我最后声明自己的协议,该协议扩展了UITableViewDataSource的一些额外要求: 协议ComposableTableViewDataSource:UITableViewDataSource { var numberOfSections:Int {get} func numberOfRows(用于Int)-> Int } 对于组合数据源,它成为符合UITableViewDataSource的简单类,并且可以使用任意数量的ComposableTableViewDataSource对象进行初始化: 最后一课ComposedTableViewDataSource:NSObject { 私有let dataSources:[ComposableTableViewDataSource] init(dataSources:ComposableTableViewDataSource …){ self.dataSources =数据源 super.init() } 私人替代init(){ fatalError(“ ComposedTableViewDataSource:必须使用带有参数的初始化程序。”) } } […]

Swift中的总编程

编辑:在这个主题上,我接受了Corecursive播客的采访。 您可以在这里找到播客插曲,以及大量其他采访https://corecursive.com/007-total-programming-using-swift-with-andre-videla Swift是一种非常好的语言,因为它试图使程序员从一开始就做正确的事情。 它鼓励的好处之一就是整体性。 总计多少? 总体程序是一种不会卡住,崩溃或陷入无限循环的程序。 它始终会在有限的时间内正确终止。 如果您的程序是完整程序且类型正确,则不会出现程序崩溃或卡住的情况¹。 程序有多种可能是不完全的。 这里有一些例子: 由于死锁或无限循环而陷入困境 边缘情况不予处理,将使程序崩溃 输入格式错误会使程序处于损坏状态 因此,总体上体现了“打字正确的程序不会出错”的短语²。 此属性在日常编程中非常有用,因为它可以减轻(但不能消除)对测试的需求,可以增加对代码的信心,并可以将代码库视为可信任的小块。 大多数正在使用的程序都不是完整的,例如,大多数程序旨在永久运行(Web服务器,移动应用程序,恶魔)。 但是,即使整个程序不是全部,将部分内容汇总也是很有用的。 尽管我将讨论“全部程序”,但实际上它们将是“全部功能”,因此我将可互换地使用两个词。 在这篇文章中,我将介绍空指针和未检查的异常如何针对整体性工作,然后,我将展示Swift如何通过解决这两个问题来鼓励整体性。 之后,我们将看到如何使用!默默地打破Swift的承诺! 运算符在不同的上下文中,并给出一些如何避免编写简单安全代码的示例! 。 尽管总体主题与非终止有着深深的联系,但我不会谈论它。 (注1:这一切都很好,但是Swift绝对不会检查您的程序是否完整。它只是鼓励几乎偶然地使程序完整的做法。Swift不检查整体性有很多原因,但最引人注目的是从数学上讲这是不可能的。 实际上,检查整体性意味着检查程序将始终终止(无无限循环),并终止于“良好”状态(无崩溃)。 终止问题通常被称为“停止问题”,该问题已被推广,并被艾伦·图灵(Alan Turing)使用其图灵机证明无法解决。 现有的编程语言具有有限的终止检查形式,例如Idris或Agda,但是给定了任意程序,他们无法决定它是否终止。 因此,他们将无法判断该程序是否完整。) (脚注2:此短语的原始来源 来自Milner的 这篇论文 。此声明的上下文是该特定类型系统存在健全性证明,因此,任何类型良好的表达都是声音。) 空引用在低级语言中找到其起源,程序员在该语言中操纵指向内存³中值的指针。 这种语言大量使用指针来访问内存中的地址,这些地址保存了程序中使用的所有数据结构。 例如,在链接列表中,通常将每个节点表示为一对指针:指向当前保存的值的指针和指向列表中下一个节点的指针。 此外,这也使得在列表末尾添加元素变得更加麻烦,因为您将不得不创建一个中间节点,将最后一个节点的值放在新的中间节点中,并使最后一个节点的前任指向新的中间节点,用新值替换最后一个节点中的值,使新的中间节点指向最后一个节点。 实现最后一个元素的另一种方法是使最后一个指针“悬空”而不指向任何东西。 例如,它可以指向未在内存中初始化的特殊保留值(例如0)。 由于所有这些“悬挂”指针都是相同的,因此我们可以轻松地对其进行比较。 因为我们经常使用此类指针,所以我们给它指定了一个名称,并将其称为null 。 现在,我们可以通过简单地将最终空指针替换为指向新的最后一个元素的指针,并将最后一个元素的尾部指针设置为null来在列表的末尾添加元素。 这使我们的LinkedList API更简单,更优雅,但代价是安全。 实际上,取消引用这样的指针通常会导致程序崩溃,因为您正在访问未初始化的内存。 空引用继承给其他编程语言(如Java,C#和其他语言),以便以与C完全相同的方式表示诸如链表之类的数据结构。在这些语言中,指针不再是一等公民,但我们仍然可以拥有NullPointerException或尝试使用引用而没有意识到它为null NullReferenceException 。 (注3:空指针被Tony Hoare称为“十亿美元的错误”,他于1965年在Algol W中引入了空引用。我鼓励您在 https://www.infoq 上听听他关于空引用的论述 。 […]