这是一个 Swift 微框架,提供了一些我在许多其他框架中使用的简单函数。我将它们集中在这里,而不是继续为每个消费者重新实现它们。
值得注意的是,这个框架不提供任何新的类型,也不提供任何对自定义类型进行操作的函数;这些函数大概属于它们自己的微框架。
Prelude 的函数非常有用。这里是一些你可以用它们做的事情的概览。
将 id
作为参数传递给 Stream
的 Stream
的 flattenMap
方法,会将其展平为包含所有嵌套元素的流
func flatten<T>(stream: Stream<Stream<T>>) -> Stream<T> {
return stream.flattenMap(id)
}
将 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
来创建一个匿名函数,它可以递归地调用自身
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
结合使用,以将数据传递到高阶函数链中,例如 sorted
、map
和 reduce
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
柯里化接受一个参数数量大于 1 的函数,并返回一个单参数函数,该函数返回一个单参数函数,依此类推。 也就是说,给定 (T, U) -> V
,柯里化返回 T -> U -> V
。
当制作更有趣的函数(例如 <|
)时,这尤其有用。
使用非交换运算符(如 -
和 /
)时,使用 <|
的伪运算符分节可能会有点令人惊讶: (-) <| 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)
Swift 的元组非常方便,但有时当您得到一个元组时,它的顺序是错误的。 swap
对元组的作用类似于 flip
对函数的作用:它颠倒它们的顺序。
map(enumerate("hello"), swap) // => [(h, 0), (e, 1), (l, 2), (l, 3), (o, 4)]
从元组中获取一个值是一个常见操作,可以使用 first
和 second
函数来表示。 运算符相应地提供包含两个元素的元组的第一个和第二个值。
[(0,0), (5, 1), (9, 2)].map(second) // => [0, 1, 2]
完整的 API 文档在源代码中。
Prelude.xcodeproj
拖到您的项目或工作区中。Prelude.framework
。或者使用 Swift 包管理器并将此添加到您的 Package.swift
文件中
...
dependencies: [
...
.package(url: "https://github.com/robrix/Prelude", "3.0.0" ..< "4.0.0")
],
targets: [
...
.target(
name: "<YourTargetName>",
dependencies: ["Prelude"]),
]