You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: RATIONALE.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -77,7 +77,7 @@ How can we be sure that a certain type is a *proper* `BoundedSemilattice`? In fa
77
77
78
78
One of the main points of the `Abstract` library is providing the user with simple means to test concrete types against the laws that the type must respect.
79
79
80
-
The `Law` and `LawInContext` namespaces provide some functions for types for which the `<>` operation is supposed to respect some laws; these functions require that the tested type is `Equatable` because the `==` operation is used to check if the equations that express the law evaluate into `true` or `false`. Because at the present moment there's no possibility of conditional conformance to the `Equatable` protocol in Swift's type system, all the concrete types in `Abstract` are made to conform either to `Equatable` or `EquatableInContext` (the latter is used for types that wrap functions). When conditional conformance [will be implemented](https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md) into Swift, there will be a `Equatable` implementation for the various types only under certain assumptions.
80
+
The `Law` and `LawInContext` namespaces provide some functions for types for which the `<>` operation is supposed to respect some laws; these functions require that the tested type is `Equatable` because the `==` operation is used to check if the equations that express the law evaluate into `true` or `false`.
81
81
82
82
------
83
83
@@ -108,4 +108,4 @@ Mistakes are bad, and should be corrected. But I think it's extremely important
108
108
109
109
A plain translation into Swift from a language with a more sophisticated type system will almost certainly result in something ugly and impractical. On the other hand, I'm also interested in pushing the boundaries of Swift's expressivity, thus I think it's ok to do stuff a little less rigorous (without losing laws conformance or writing unsound code, of course) but much more practically usable.
110
110
111
-
I hope that this library will inspire people to find new and interesting ways to take advantage of the basic theoretical concepts of abstract algebra in their day-to-day Swift code, while also trying to push the boundaries of Swift, thus contributing to the general improvement of the language in the process.
111
+
I hope that this library will inspire people to find new and interesting ways to take advantage of the basic theoretical concepts of abstract algebra in their day-to-day Swift code, while also trying to push the boundaries of Swift, thus contributing to the general improvement of the language in the process.
Copy file name to clipboardExpand all lines: README.md
+18-13Lines changed: 18 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Abstract
2
2
3
-
A take on abstract algebraic structures, in Swift.
3
+
A take on abstract algebraic structures, in Swift.
4
4
5
5
------
6
6
@@ -237,10 +237,10 @@ Notice that we could call `.reduce(.empty, <>)` on **any** collection were the e
237
237
- can be composed with `<>`;
238
238
- have an empty element;
239
239
240
-
Thus, if we were able to represent these two properties in an abstract way, we could simply define a `.concatenated` method for these kinds of collections:
240
+
Thus, if we were able to represent these two properties in an abstract way, we could simply define a `.concatenated()` method for these kinds of collections:
241
241
242
242
```swift
243
-
let finalSession = sessions.concatenated
243
+
let finalSession = sessions.concatenated()
244
244
```
245
245
246
246
A type (actually a set, but in programming we really just care about types) *equipped* with a composition operation that is *closed* (i.e. non-crashing) and *associative*, and an `.empty` value that is neutral to the composition, is usually called a `Monoid`: all the types defined in this example are monoids, and the Swift type system is strong enough to generically define the interface of a monoid with a `protocol`. Most of the types and methods used in this example are already defined in `Abstract`, and to read more about monoids you can refer to the [Monoid.swift](Sources/Abstract/Monoid.swift) source file.
@@ -260,19 +260,19 @@ Let's call "special divisors" the numbers associated to each word (initially, 3
260
260
261
261
The first composition style is simple concatenation; the second one is a little harder to see as some kind of composition, but it actually is the composition where we get only the first value if it exists (even if both exist), otherwise we get the second, and if none exist we get an "empty" value.
262
262
263
-
The type representing the string concatenation is simply `String`, which naturally forms a monoid over concatenation, where the `.empty` value is just the empty string. For the second type of composition we need a special type, that in `Abstract` is called `FirstM`: in composition, it will give priority to the first value.
263
+
The type representing the string concatenation is simply `String`, which naturally forms a monoid over concatenation, where the `.empty` value is just the empty string.
264
264
265
265
About the simple string concatenation, we'd like to define a function that *associates* a *word* to a special divisor: the function will take an `Int` and return a `String`, which is going to be "Fizz" or "Buzz". But instead of concatenating words we would actually like to concatenate *functions* that return words: if we're able to compose the return value, we can actually define a *composable function*:
The `FunctionM` type is a *function type* (we get the function back with the `.call` method) that's **also** a monoid, so we can compose and concatenate instances of this function like we'd do for `String` values.
275
+
The `Function` type is a *function type* (we get the function back with the `.call` method) that's **also** a monoid, so we can compose and concatenate instances of this function like we'd do for `String` values.
276
276
277
277
We can easily define our `fizz` and `buzz` associations:
278
278
@@ -284,14 +284,19 @@ let buzz = associate(divisor: 5, to: "Buzz")
284
284
Now we can easily generate a function that will transform a number in a word, properly concatenated (like "FizzBuzz" for the number 15), or an empty string if the number has no special divisor.
285
285
286
286
```swift
287
-
let transform = [fizz, buzz].concatenated.call
287
+
let transform = [fizz, buzz].concatenated().call
288
288
```
289
289
290
-
Finally, we need a second kind of composition: the one in which the first value is selected if it's not `.empty`. The `FirstM` type has exactly this semantics. We can define a `getWord` function that will use `FirstM` to select a value in a composition:
290
+
For the second type of composition, Swift already provides a type with the correct semantics; we need to give priority to the *first* element, but only if it's not `.empty`, otherwise we yield the second value (`.empty` or not): that's exactly the composition semantics of `Optional`, where `.empty` is `.none` (or `nil`) and the composition operation is represented by the `??` operator. `Abstract` extends `Optional` with the `Monoid` protocol, adding the `.empty` instance and the `<>` operator. We can define a `getWord` function that will use `Optional<String>` to select a value in a composition:
@@ -311,7 +316,7 @@ Now that we've separated the two kinds of composition that are taking place here
311
316
312
317
```swift
313
318
let bazz =associate(divisor: 4, to: "Bazz")
314
-
let transform = [fizz, buzz, bazz].concatenated.call
319
+
let transform = [fizz, buzz, bazz].concatenated().call
315
320
```
316
321
317
322
This code will add the word "Bazz" to the mix, for all numbers divisible by 4. Notice that in our example, for the number 60 the word "FizzBuzzBazz" will be printed: the order matters here, and we get "Bazz" at the end because we composed our transformation like `[fizz, buzz, bazz]`.
0 commit comments