PointFree-Gen 0.2.0

PointFree-Gen 0.2.0

Stephen CelisBrandon Williams维护。



🎱Gen

Swift 5 iOS/macOS/tvOS/watchOS CI Linux CI @pointfreeco

可组合、可变换、可控制随机性。

目录

动机

Swift 的随机数 API 功能强大且易于使用。它允许我们从许多基本类型(例如布尔值和数值类型)创建随机值,并且允许我们随机打乱数组和从集合中抽取随机元素。

但是,它并没有让我们容易地扩展随机数 API,也没有提供可组合的 API,这样我们就可以从更简单的单元创建更复杂的随机类型。

Gen 是 Swift 随机数 API 的一种轻量级包装器,可以轻松构建任何类型的自定义生成器。

示例

Gen 的同名类型 Gen 负责产生随机值。通常,您会使用 Gen 中的一个静态变量来获取 Gen 值。

Gen.bool
// Gen<Bool>

Gen 不是立即生成随机值,而是描述一个可以通过调用其 run 方法生成的随机值。

let myGen = Gen.bool
// Gen<Bool>

myGen.run() // true
myGen.run() // true
myGen.run() // false

Swift 中的每个随机函数都可以在 Gen 的静态函数上使用。

Swift 的 API Gen 的 API
Int.random(in: 0...9) Gen.int(in: 0...9)
Double.random(in: 0...9) Gen.double(in: 0...9)
Bool.random() Gen.bool
[1, 2, 3].randomElement() 生成元素为:[1, 2, 3]的生成器
将[1, 2, 3]进行随机排序 使用Gen.shuffle([1, 2, 3])进行排序

使用Gen类型包装随机性的强大之处在于,我们可以使Gen类型可组合。例如,整数生成器可以通过简单的map函数转换为一个数字字符串生成器

let digit = Gen.int(in: 0...9)           // Gen<Int>
let stringDigit = digit.map(String.init) // Gen<String>

stringDigit.run() // "7"
stringDigit.run() // "1"
stringDigit.run() // "3"

这已经是一种Swift API默认不提供的随机性形式。

Gen提供了许多生成新类型随机性的运算符,例如mapflatMapzip,以及用于生成随机数组、集合、字典、字符串、分布等的辅助函数!例如,随机密码生成器只需几个运算符。

// Take a generator of random letters and numbers.
let password = Gen.letterOrNumber
  // Generate 6-character strings of them.
  .string(of: .always(6))
  // Generate 3 segments of these strings.
  .array(of: .always(3))
  // And join them.
  .map { $0.joined(separator: "-") }

password.run() // "9BiGYA-fmvsOf-VYDtDv"
password.run() // "dS2MGr-FQSuC4-ZLEicl"
password.run() // "YusZGF-HILrCo-rNGfCA"

这种组合方式使得我们可以简单地生成任何内容的随机值。

// Use `zip` to combine generators together and build structures.

let randomPoint = zip(.int(in: -10...10), .int(in: -10...10))
  .map(CGPoint.init(x:y:))
// Gen<CGPoint>

但组合性并不是Gen类型闪光的唯一原因。通过延迟随机值的创建,直到调用run方法,我们可以控制需要确定性的环境中的随机性,例如测试。`run`方法有一个重载版本,它接受一个RandomNumberGenerator值,这是Swift的协议,为其随机API提供动力。默认情况下,它使用SystemRandomNumberGenerator,这是一个良好的随机数来源,但我们也可以提供一个可播种的“伪”随机数生成器,以便在测试中获得可预测的结果。

var lcrng = LCRNG(seed: 0)
Gen.int(in: 0...9).run(using: &lcrng) // "8"
Gen.int(in: 0...9).run(using: &lcrng) // "1"
Gen.int(in: 0...9).run(using: &lcrng) // "7"

lcrng.seed = 0
Gen.int(in: 0...9).run(using: &lcrng) // "8"
Gen.int(in: 0...9).run(using: &lcrng) // "1"
Gen.int(in: 0...9).run(using: &lcrng) // "7"

这意味着您不必在应用中使用随机性时牺牲可测试性。

有关使用Gen构建复杂随机性的更多示例,请参阅我们关于创建Zalgo生成器的博客文章,以及关于创建生成式艺术的两个部分视频系列(第1部分第2部分)。

安装

Carthage

如果您使用Carthage,请将以下依赖项添加到您的Cartfile

github "pointfreeco/swift-gen" ~> 0.1

CocoaPods

如果您的项目使用CocoaPods,只需将其添加到您的Podfile

pod 'PointFree-Gen', '~> 0.1'

SwiftPM

如果您想在使用 SwiftPM 的项目中使用 Gen,只需在您的 Package.swift 文件中添加一个 dependencies 条款即可。

dependencies: [
  .package(url: "https://github.com/pointfreeco/swift-gen.git", from: "0.1.0")
]

Xcode Sub-project

将 Gen 作为子模块克隆或下载,然后将 Gen.xcodeproj 拖入您的项目中。

想要了解更多?

这些概念(以及其他概念)在 Point-Free 中得到了深入探讨,这是一个由 Brandon WilliamsStephen Celis 主持的功能式编程和 Swift 视频系列。

本库的设计在以下 Point-Free 集中进行了探讨

video poster image

许可证

所有模块均采用 MIT 许可证发布。有关详细信息,请参阅 LICENSE