序言

这是一个 Swift 微框架,提供了一些我在许多其他框架中使用的简单函数。我将它们集中在这里,而不是继续为每个消费者重新实现它们。

值得注意的是,这个框架不提供任何新的类型,也不提供任何对自定义类型进行操作的函数;这些函数大概属于它们自己的微框架。

目录

概览

Prelude 的函数非常有用。这里是一些你可以用它们做的事情的概览。

id

id 作为参数传递给 StreamStreamflattenMap 方法,会将其展平为包含所有嵌套元素的流

func flatten<T>(stream: Stream<Stream<T>>) -> Stream<T> {
	return stream.flattenMap(id)
}

const

const 的结果传递给 Either 可以方便地将其转换为 Optional<T>

let result: Either<NSError, String> = 
if let string = result.either(const(nil), id) {
	println("ohai \($0)")
}

>>><<<

从左到右和从右到左的组合运算符(分别为 >>><<<)将操作链接在一起

let repl: File -> String = readLine >>> parseString >>> evaluateAST >>> toString
while true {
	println(repl(standardInput))
}

fix

你可以使用 fix 来创建一个匿名函数,它可以递归地调用自身

let factorial = fix { recur in
	{ n in n > 0 ? n * recur(n - 1) : 1 }
}

|><|

前向和后向应用运算符(分别为 |><|)将它们指向一侧的函数应用于另一侧的值。

这有时可以使代码更具可读性。对于前向应用运算符来说尤其如此。 x |> f 等价于 f(x),但它按照数据流动的方向读取。 对于更长的函数名称,其好处更加明显

100 |> toString |> count // => 3
// this is equivalent to
countElements(toString(100))

后向应用在这种情况下读取方向错误—f <| x 实际上并没有比 f(x) 更好。 然而,与前向应用不同,<| 可以将二元和三元函数应用于它们的第一个操作数。 这使您能够创建类似于 Haskell 的运算符部分 的东西

let successor: Int -> Int = (+) <| 1
successor(3) // => 4
map([1, 2, 3], (*) <| 2) // => [2, 4, 6]

您还可以将 |><|flip 结合使用,以将数据传递到高阶函数链中,例如 sortedmapreduce

let result =
	[66, 78, 1, 95, 76]
|>	(flip(sorted) <| (<)) // sort in ascending order
|>	(flip(map) <| toString) // make them into strings
|>	String.join(", ") // comma-separate them

let sum: [Int] -> Int = flip(reduce) <| (+) <| 0

由于 Swift 函数也可以应用于其参数的元组,因此您也可以通过将元组放在另一侧来将 |><| 与二元、三元等函数一起使用

(1, 2) |> (+) // => 3

curry

柯里化接受一个参数数量大于 1 的函数,并返回一个单参数函数,该函数返回一个单参数函数,依此类推。 也就是说,给定 (T, U) -> V,柯里化返回 T -> U -> V

当制作更有趣的函数(例如 <|)时,这尤其有用。

flip

使用非交换运算符(如 -/)时,使用 <| 的伪运算符分节可能会有点令人惊讶: (-) <| 1 的意思是 { 1 - $0 },这与 { $0 - 1 } 非常不同。 您可以使用 flip 来生成后者

map([1, 2, 3], (-) <| 1) // => [0, -1, -2]
map([1, 2, 3], flip(-) <| 1) // => [0, 1, 2]

&&&

Optional 有一个 map 方法,当您想要将函数应用于非 nil 值,或者在其他情况下返回 nil 时,这正是您所需要的。 当您有两个 Optional 值时,可以使用 &&& 来组合它们

let (x: Int?, y: Int?) = (2, 2)
(x &&& y).map(+) // => .Some(4)

swap

Swift 的元组非常方便,但有时当您得到一个元组时,它的顺序是错误的。 swap 对元组的作用类似于 flip 对函数的作用:它颠倒它们的顺序。

map(enumerate("hello"), swap) // => [(h, 0), (e, 1), (l, 2), (l, 3), (o, 4)]

firstsecond

从元组中获取一个值是一个常见操作,可以使用 firstsecond 函数来表示。 运算符相应地提供包含两个元素的元组的第一个和第二个值。

[(0,0), (5, 1), (9, 2)].map(second) // => [0, 1, 2]

文档

完整的 API 文档在源代码中。

集成

  1. 将此存储库添加为子模块并检出其依赖项,和/或如果您使用 carthage 来管理您的依赖项,将其添加到您的 Cartfile 中。
  2. Prelude.xcodeproj 拖到您的项目或工作区中。
  3. 将您的目标链接到 Prelude.framework
  4. 应用程序目标应确保框架被复制到其应用程序包中。 (框架目标应改为要求链接它们的应用程序包含 Prelude。)

或者使用 Swift 包管理器并将此添加到您的 Package.swift 文件中

  ...
  dependencies: [
    ...  
    .package(url: "https://github.com/robrix/Prelude", "3.0.0" ..< "4.0.0")
  ],
  targets: [
    ...
    .target(
        name: "<YourTargetName>",
        dependencies: ["Prelude"]),
  ]