Skip to content

Commit 2db6162

Browse files
authored
Merge pull request #32 from broomburgo/master
fixed some typos in README
2 parents 3d4e87e + ead45c3 commit 2db6162

File tree

1 file changed

+10
-10
lines changed

1 file changed

+10
-10
lines changed

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A take on abstract algebraic structures, in Swift.
44

55
------
66

7-
`Abstract` is a Swift library that defines protocols for the main [abstract algebraic structures](https://en.wikipedia.org/wiki/Abstract_algebra), along with some concrete implementations for Swift datatypes.
7+
`Abstract` is a Swift library that defines protocols for common [abstract algebraic structures](https://en.wikipedia.org/wiki/Abstract_algebra), along with some concrete implementations for Swift datatypes.
88

99
The library also provides tools to test the concrete types for the axioms required by each algebraic structure: tests can then be performed by property-based testing libraries like [SwiftCheck](https://github.com/typelift/SwiftCheck).
1010

@@ -93,9 +93,9 @@ var maxCookiesPerRequest: Max<Int>
9393
var alwaysSatisfied: And
9494
```
9595

96-
Each property is of a type that specifies how we're supposed to *compose* two instances: `Max<Date>` will always keep the highest of two dates, and it's going to be the same for `Max<Int>` but for numbers; `Add<Int>` will compose the number by adding them, and `And` will apply the `&&` operation to two `Bool`. We can then get the *wrapped* value inside the type with an `unwrap` function.
96+
Each property is of a type that specifies how we're supposed to *compose* two instances: `Max<Date>` will always keep the highest of two dates, and it's going to be the same for `Max<Int>` but for numbers; `Add<Int>` will compose the numbers by adding them, and `And` will apply the `&&` operation to two `Bool`. We can then get the *wrapped* value inside the type with an `unwrap` function.
9797

98-
Following this strategy we can actually define an `Average` type the declares a composition function that works as intended:
98+
Following this strategy we can actually define an `Average` type that declares a composition function that works as intended:
9999

100100
```swift
101101
struct Average {
@@ -211,7 +211,7 @@ let averageCookiesPerRequest = finalSession.averageCookiesPerRequest.unwrap // 4
211211
let alwaysSatisfied = finalSession.alwaysSatisfied.unwrap // false
212212
```
213213

214-
If we provide an `.empty` value also for `UserSession` we can actually collect all the interactions in an `Array`, and then `reduce` the collection. This is definitely more convenient and readable, and allows us to separate the *collection* of the data from their *processing*. `UserSession.empty` will naturally be an instance were every property is `.empty`:
214+
If we provide an `.empty` value also for `UserSession` we can actually collect all the interactions in an `Array`, and then `reduce` the collection. This is definitely more convenient and readable, and allows us to separate the *collection* of the data from their *processing*. `UserSession.empty` will naturally be an instance where every property is `.empty`:
215215

216216
```swift
217217
let sessions: [UserSession] = [
@@ -240,7 +240,7 @@ Thus, if we were able to represent these two properties in an abstract way, we c
240240
let finalSession = sessions.concatenated
241241
```
242242

243-
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` valued 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.
243+
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.
244244

245245
### FizzBuzzNess
246246

@@ -257,7 +257,7 @@ Let's call "special divisors" the numbers associated to each word (initially, 3
257257

258258
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.
259259

260-
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.
260+
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.
261261

262262
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*:
263263

@@ -269,7 +269,7 @@ func associate(divisor: Int, to text: String) -> FunctionM<Int,String> {
269269
}
270270
```
271271

272-
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.
272+
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.
273273

274274
We can easily define our `fizz` and `buzz` associations:
275275

@@ -323,7 +323,7 @@ struct Process<T> {
323323
}
324324
```
325325

326-
Let's also assume we have a bunch of processes that we want to run, and then combine all the values into a single one. Running all the processes in sequence and then collecting all the values could be tedious and inefficient, but running them in parallel, maybe in a distributed way, could be dangerous, unpredictable and hard to coordinate.
326+
Let's also assume that we have a bunch of processes that we want to run, and then combine all the values into a single one. Running all the processes in sequence and then collecting all the values could be tedious and inefficient, but running them in parallel, maybe in a distributed way, could be dangerous, unpredictable and hard to coordinate.
327327

328328
We would like to take advantage of the abstract algebraic structures defined in `Abstract` to simplify the problem. Everything depends on the `T` value: it turns out that, if `T` has certain properties, we can actually run our processes in a distributed and efficient way without any risk.
329329

@@ -361,7 +361,7 @@ extension DispatchQueue: Context {
361361
}
362362
```
363363

364-
A `Collector` class will receive all the `T` values and combine them together: the requirement on `T`, in this case, is for it to be a `Monoid`, so it has an `.empty` value and a `<>` composition operation.
364+
A `Collector` class will receive all the `T` values and combine them together: the requirement on `T`, in this case, is for it to be a monoid, so it has an `.empty` value and a `<>` associative composition operation.
365365

366366
```swift
367367
class Collector<T: Monoid> {
@@ -386,7 +386,7 @@ class Distributor {
386386

387387
Notice that, if the only constraint that we impose on `T` is `Monoid` (in the code above the requirement is implicit) we cannot do much more than distributing the work on a serial queue, because we need the processes to run and complete in the same order as they're passed to the distributor.
388388

389-
An improvement over this would be if `T` was a `CommutativeMonoid`: in this case the `<>` operation is declared to be commutative, which means that the order of composition doesn't matter. This way we can distribute work over a concurrent queue: even if a process add before another completes after it, the commutativity will insure that the composition will still make sense.
389+
An improvement over this would be if `T` was a `CommutativeMonoid`: in this case the `<>` operation is declared to be commutative, which means that the order of composition doesn't matter. This way we can distribute work over a concurrent queue: even if a process ends before one that started earlier, the commutativity will insure that the composition still makes sense.
390390

391391
```swift
392392
class Distributor {

0 commit comments

Comments
 (0)