Skip to content

Commit 9750466

Browse files
authored
Merge pull request #1 from RougeWare/feature/MVP
MVP
2 parents 1357832 + 5e4f82e commit 9750466

File tree

13 files changed

+615
-2
lines changed

13 files changed

+615
-2
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/

.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>IDEDidComputeMac32BitWarning</key>
6+
<true/>
7+
</dict>
8+
</plist>

Package.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// swift-tools-version:5.2
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "FunctionTools",
8+
products: [
9+
// Products define the executables and libraries produced by a package, and make them visible to other packages.
10+
.library(
11+
name: "FunctionTools",
12+
targets: ["FunctionTools"]),
13+
],
14+
dependencies: [
15+
// Dependencies declare other packages that this package depends on.
16+
// .package(url: /* package url */, from: "1.0.0"),
17+
],
18+
targets: [
19+
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
20+
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
21+
.target(
22+
name: "FunctionTools",
23+
dependencies: []),
24+
.testTarget(
25+
name: "FunctionToolsTests",
26+
dependencies: ["FunctionTools"]),
27+
]
28+
)

README.md

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,92 @@
1-
# Swift-Function-Tools
2-
Some tools to make functions easier to use in Swift
1+
# Function Tools #
2+
3+
Some basic tools for functional programming
4+
5+
6+
## `blackhole` ##
7+
8+
Simply functions which take a value and do nothing with it. Useful for testing and mocks.
9+
For example:
10+
```swift
11+
stuff.forEach(blackhole)
12+
```
13+
14+
15+
## `null` ##
16+
17+
Like `blackhole`, this simply functions which take a value and do nothing with it. Unlike `blackhole`, this will always be optimized away in production code. Useful for giving to functions which demand a callback, when you don't have anything to do after it calls back.
18+
For example:
19+
```swift
20+
myObject.someAsyncFunction(onComplete: null)
21+
```
22+
23+
24+
## `call` ##
25+
26+
A utility function which simply calls the given function. This is useful for compressing higher-order functions.
27+
For example:
28+
```swift
29+
let someFunctions: [BlindCallback] = [
30+
{ print("Hello") },
31+
{ print("World!") },
32+
]
33+
34+
someFunctions.forEach(call)
35+
```
36+
37+
38+
## `curry` ##
39+
40+
Converts a non-currying function into a currying function.
41+
For example:
42+
```swift
43+
let add = curry(+)
44+
[1, 2, 3, 4].map(add(4)) // [5, 6, 7, 8]
45+
```
46+
47+
48+
## Function Types ##
49+
50+
Some typealiases for common functions:
51+
52+
53+
54+
### Callbacks ###
55+
56+
* `BlindCallback` and `ThrowingBlindCallback`
57+
* A function that you'd pass to another one as a callback, which doesn't need to know anything nor report anything
58+
* `Callback` and `ThrowingCallback`
59+
* A function that you'd pass to another one as a callback, which needs to know the result of the other one
60+
61+
62+
### Transformer family of functions ###
63+
64+
* `Transformer` and `ThrowingTransformer`
65+
* A function which can transform one thing into another, like the kind you pass to a `map` function
66+
67+
* `Filter` and `ThrowingFilter`
68+
* A function which can filter a sequence of elements, like the kind you pass to a `filter` function
69+
70+
71+
### Generator family of functions ###
72+
73+
* `Generator` and `ThrowingGenerator`
74+
* A function which can generate one thing without any input, like in an `@autoclosure`
75+
76+
77+
### Reducer family of functions ###
78+
79+
* `Reducer` and `ThrowingReducer`
80+
* A function which can reduce a sequence of elements into one value, like the kind you pass to a `reduce` function
81+
82+
* `AllocationReducer` and `ThrowingAllocationReducer`
83+
* A function which can reduce a sequence of elements into one value by allocating new reductions, like the kind you pass to a `reduce` function. Often slower than `Reducer`.
84+
85+
86+
### Combinator family ###
87+
88+
* `Combinator` and `ThrowingCombinator`
89+
* A function which can combine two values into one
90+
91+
* `CurriedCombinator`
92+
* A function which can combine two values into one, over the course of multiple separate function calls.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//
2+
// Blackholes.swift
3+
// FunctionTools
4+
//
5+
// Created by Ben Leggiero on 2020-04-02.
6+
// Copyright © 2020 Ben Leggiero BS-1-PS.
7+
//
8+
9+
10+
11+
/// This guarantees that even the most scrutinous of optimizers will never optimize-away these blackholes
12+
private var blackholeAcceptor: Any? {
13+
didSet {
14+
blackholeAcceptor = nil
15+
}
16+
}
17+
18+
19+
/// A function which does nothing, but will never be optimized away. Useful for testing.
20+
///
21+
/// - SeeAlso: `null`
22+
@inline(never)
23+
public func blackhole() -> Void { }
24+
25+
26+
/// A function which takes one value and does nothing with it, but will never be optimized away. Useful for testing.
27+
///
28+
/// For example:
29+
/// ```swift
30+
/// stuff.forEach(blackhole)
31+
/// ```
32+
///
33+
/// ```
34+
/// struct MySwiftUIView_Previews: PreviewProvider {
35+
/// static var previews: some View {
36+
/// Group {
37+
/// MySwiftUIView(callback: blackhole)
38+
/// }
39+
/// }
40+
/// }
41+
/// ```
42+
///
43+
/// - Parameter a: Anything at all
44+
///
45+
/// - SeeAlso: `null`
46+
@inline(never)
47+
public func blackhole<A>(_ a: A) -> Void { blackholeAcceptor = a }
48+
49+
50+
/// A function which takes two values and does nothing with them, but will never be optimized away. Useful for testing.
51+
///
52+
/// - Parameters:
53+
/// - a: Anything at all
54+
/// - b: Anything at all
55+
///
56+
/// - SeeAlso: `null`
57+
@inline(never)
58+
public func blackhole<A, B>(_ a: A, _ b: B) -> Void { blackholeAcceptor = (a, b) }
59+
60+
61+
/// A function which takes three values and does nothing with them, but will never be optimized away. Useful for testing.
62+
///
63+
/// - Parameters:
64+
/// - a: Anything at all
65+
/// - b: Anything at all
66+
/// - c: Anything at all
67+
///
68+
/// - SeeAlso: `null`
69+
@inline(never)
70+
public func blackhole<A, B, C>(_ a: A, _ b: B, _ c: C) -> Void { blackholeAcceptor = (a, b, c) }
71+
72+
73+
/// A function which takes four values and does nothing with them, but will never be optimized away. Useful for testing.
74+
///
75+
/// - Parameters:
76+
/// - a: Anything at all
77+
/// - b: Anything at all
78+
/// - c: Anything at all
79+
/// - d: Anything at all
80+
///
81+
/// - SeeAlso: `null`
82+
@inline(never)
83+
public func blackhole<A, B, C, D>(_ a: A, _ b: B, _ c: C, _ d: D) -> Void { blackholeAcceptor = (a, b, c, d) }
84+
85+
86+
/// A function which takes five values and does nothing with them, but will never be optimized away. Useful for testing.
87+
///
88+
/// - Parameters:
89+
/// - a: Anything at all
90+
/// - b: Anything at all
91+
/// - c: Anything at all
92+
/// - d: Anything at all
93+
/// - e: Anything at all
94+
///
95+
/// - SeeAlso: `null`
96+
@inline(never)
97+
public func blackhole<A, B, C, D, E>(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Void { blackholeAcceptor = (a, b, c, d, e) }

Sources/FunctionTools/Call.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// Call.swift
3+
// FunctionTools
4+
//
5+
// Created by Ben Leggiero on 2020-04-02.
6+
// Copyright © 2020 Ben Leggiero BS-1-PS.
7+
//
8+
9+
import Foundation
10+
11+
12+
13+
/// A utility function which simply calls the given function. This is useful for compressing higher-order functions
14+
///
15+
/// For example:
16+
/// ```swift
17+
/// let someFunctions: [BlindCallback] = [
18+
/// { print("Hello") },
19+
/// { print("World!") },
20+
/// ]
21+
///
22+
/// someFunctions.forEach(call)
23+
/// ```
24+
///
25+
/// - Parameter callee: The function to call
26+
/// - Throws: Anything `callee` throws
27+
@inlinable
28+
public func call(_ callee: ThrowingBlindCallback) rethrows {
29+
try callee()
30+
}
31+
32+
33+
34+
/// A utility function which simply calls the given function. This is useful for compressing higher-order functions
35+
///
36+
/// For example:
37+
/// ```swift
38+
/// let someFunctions: [BlindCallback] = [
39+
/// { print("Hello") },
40+
/// { print("World!") },
41+
/// ]
42+
///
43+
/// someFunctions.forEach(call)
44+
/// ```
45+
///
46+
/// - Parameter callee: The function to call
47+
@inlinable
48+
public func call(_ callee: BlindCallback) {
49+
callee()
50+
}

Sources/FunctionTools/Curry.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// Curry.swift
3+
// FunctionTools
4+
//
5+
// Created by Ben Leggiero on 2020-04-02.
6+
// Copyright © 2020 Ben Leggiero BS-1-PS.
7+
//
8+
9+
import Foundation
10+
11+
12+
13+
/// Converts a non-currying function into a currying function
14+
///
15+
/// ```swift
16+
/// let add = curry(+)
17+
/// [1, 2, 3, 4].map(add(4)) // [5, 6, 7, 8]
18+
/// ```
19+
///
20+
/// - Parameter f: The function to convert
21+
/// - Returns: A currying form of the given function
22+
func curry<A, B, C>(_ f: @escaping Combinator<A, B, C>) -> Transformer<A, Transformer<B, C>> {
23+
return { a in { b in f(a, b) } }
24+
}

0 commit comments

Comments
 (0)