Skip to content

Commit

Permalink
Add exercises! (#4)
Browse files Browse the repository at this point in the history
* Add exercises!

* Update contents.xcplayground
  • Loading branch information
stephencelis authored Mar 20, 2018
1 parent 1998e89 commit 5c16053
Show file tree
Hide file tree
Showing 15 changed files with 204 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,4 @@ import Foundation
//Result<(Data, URLResponse), Error>
//Result<Date, Never>
//Result<A, Error>?
//: [See the next page](@next) for exercises!
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*:
# Algebraic Data Types Exercises

1. What algebraic operation does the function type `(A) -> B` correspond to? Try explicitly enumerating all the values of some small cases like `(Bool) -> Bool`, `(Unit) -> Bool`, `(Bool) -> Three` and `(Three) -> Bool` to get some intuition.
*/
// TODO
/*:
2. Consider the following recursively defined data structure. Translate this type into an algebraic equation relating `List<A>` to `A`.
*/
indirect enum List<A> {
case empty
case cons(A, List<A>)
}
// TODO
/*:
3. Is `Optional<Either<A, B>>` equivalent to `Either<Optional<A>, Optional<B>>`? If not, what additional values does one type have that the other doesn’t?
*/
// TODO
/*:
4. Is `Either<Optional<A>, B>` equivalent to `Optional<Either<A, B>>`?
*/
// TODO
/*:
5. Can you overload the `*` and `+` infix operators with functions that take any type and build up an algebraic representation using `Pair` and `Either`?
*/
// TODO
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos'>
<timeline fileName='timeline.xctimeline'/>
<playground version='6.0' target-platform='macos'>
<pages>
<page name='01-Episode'/>
<page name='02-Exercises'/>
</pages>
</playground>
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,4 @@ func filter<A>(_ p: @escaping (A) -> Bool) -> ([A]) -> [A] {
Array(1...10)
|> filter { $0 > 5 }
>>> map(incr >>> square)
//: [See the next page](@next) for exercises!
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*:
# Higher-Order Functions Exercises

1. Write `curry` for functions that take 3 arguments.
*/
// TODO
/*:
2. Explore functions and methods in the Swift standard library, Foundation, and other third party code, and convert them to free functions that compose using `curry`, `zurry`, `flip`, or by hand.
*/
// TODO
/*:
3. Explore the associativity of function arrow `->`. Is it fully associative, _i.e._ is `((A) -> B) -> C` equivalent to `(A) -> ((B) -> C)`, or does it associate to only one side? Where does it parenthesize as you build deeper, curried functions?
*/
// TODO
/*:
4. Write a function, `uncurry`, that takes a curried function and returns a function that takes two arguments. When might it be useful to un-curry a function?
*/
// TODO
/*:
5. Write `reduce` as a curried, free function. What is the configuration _vs._ the data?
*/
// TODO
/*:
6. In programming languages that lack sum/enum types one is tempted to approximate them with pairs of optionals. Do this by defining a type `struct PseudoEither<A, B>` of a pair of optionals, and prevent the creation of invalid values by providing initializers.

This is “type safe” in the sense that you are not allowed to construct invalid values, but not “type safe” in the sense that the compiler is proving it to you. You must prove it to yourself.
*/
// TODO
/*:
7. Explore how the free `map` function composes with itself in order to transform a nested array. More specifically, if you have a doubly nested array `[[A]]`, then `map` could mean either the transformation on the inner array or the outer array. Can you make sense of doing `map >>> map`?
*/
// TODO
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos'>
<timeline fileName='timeline.xctimeline'/>
<playground version='6.0' target-platform='macos' display-mode='rendered'>
<pages>
<page name='01-Episode'/>
<page name='02-Exercises'/>
</pages>
</playground>
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,14 @@ public func map<A, B>(_ f: @escaping (A) -> B) -> ([A]) -> [B] {
|> first(incr)

dump(
[(42, ["Swift", "Objective-C"]), (1729, ["Haskell", "Purescript"])]
[(42, ["Swift", "Objective-C"]), (1729, ["Haskell", "PureScript"])]
|> (map <<< second <<< map) { $0 + "!" }
)

//

let data = [(42, ["Swift", "Objective-C"]), (1729, ["Haskell", "Purescript"])]
let data = [(42, ["Swift", "Objective-C"]), (1729, ["Haskell", "PureScript"])]

data
.map { ($0.0, $0.1.map { $0 + "!" }) }



//: [See the next page](@next) for exercises!
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*:
# Functional Setters Exercises

1. As we saw with free `map` on `Array`, define free `map` on `Optional` and use it to compose setters that traverse into an optional field.
*/
// TODO
/*:
2. Take the following `User` struct and write a setter for its `name` property. Add another property, and add a setter for it. What are some potential issues with building these setters?
*/
struct User {
let name: String
}
// TODO
/*:
3. Add a `location` property to `User`, which holds a `Location`, defined below. Write a setter for `userLocationName`. Now write setters for `userLocation` and `locationName`. How do these setters compose?
*/
struct Location {
let name: String
}
// TODO
/*:
4. Do `first` and `second` work with tuples of three or more values? Can we write `first`, `second`, `third`, and `nth` for tuples of _n_ values?
*/
// TODO
/*:
5. Write a setter for a dictionary that traverses into a key to set a value.
*/
// TODO
/*:
6. What is the difference between a function of the form `((A) -> B) -> (C) -> (D)` and one of the form `(A) -> (B) -> (C) -> D`?
*/
// TODO
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos'>
<timeline fileName='timeline.xctimeline'/>
<playground version='6.0' target-platform='macos' display-mode='rendered'>
<pages>
<page name='01-Episode'/>
<page name='02-Exercises'/>
</pages>
</playground>
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,5 @@ User.template
let boringLocal = .template
|> noFavoriteFoods
|> domestic


//: [See the next page](@next) for exercises!

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*:
# Setters and Key Paths Exercises

1. In this episode we used `Dictionary`’s subscript key path without explaining it much. For a `key: Key`, one can construct a key path `\.[key]` for setting a value associated with `key`. What is the signature of the setter `prop(\.[key])`? Explain the difference between this setter and the setter `prop(\.[key]) <<< map`, where `map` is the optional map.
*/
// TODO
/*:
2. The `Set<A>` type in Swift does not have any key paths that we can use for adding and removing values. However, that shouldn't stop us from defining a functional setter! Define a function `elem` with signature `(A) -> ((Bool) -> Bool) -> (Set<A>) -> Set<A>`, which is a functional setter that allows one to add and remove a value `a: A` to a set by providing a transformation `(Bool) -> Bool`, where the input determines if the value is already in the set and the output determines if the value should be included.
*/
// TODO
/*:
3. Generalizing exercise #1 a bit, it turns out that all subscript methods on a type get a compiler generated key path. Use array’s subscript key path to uppercase the first favorite food for a user. What happens if the user’s favorite food array is empty?
*/
// TODO
/*:
4. Recall from a [previous episode](https://www.pointfree.co/episodes/ep5-higher-order-functions) that the free `filter` function on arrays has the signature `((A) -> Bool) -> ([A]) -> [A]`. That’s kinda setter-like! What does the composed setter `prop(\\User.favoriteFoods) <<< filter` represent?
*/
// TODO
/*:
5. Define the `Result<Value, Error>` type, and create `value` and `error` setters for safely traversing into those cases.
*/
// TODO
/*:
6. Is it possible to make key path setters work with `enum`s?
*/
// TODO
/*:
7. Redefine some of our setters in terms of `inout`. How does the type signature and composition change?
*/
// TODO
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos'>
<timeline fileName='timeline.xctimeline'/>
<playground version='6.0' target-platform='macos' display-mode='rendered'>
<pages>
<page name='01-Episode'/>
<page name='02-Exercises'/>
</pages>
</playground>
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,4 @@ users.sorted(by: their(^\.email, >))

users.max(by: their(^\.email.count))?.email
users.min(by: their(^\.email.count))?.email

import Foundation

//NSObject().observe(<#T##keyPath: KeyPath<NSObject, Value>##KeyPath<NSObject, Value>#>, changeHandler: <#T##(NSObject, NSKeyValueObservedChange<Value>) -> Void#>)








//: [See the next page](@next) for exercises!
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*:
# Getters and Key Paths Exercises

1. Find three more standard library APIs that can be used with our `get` and `^` helpers.
*/
// TODO
/*:
2. The one downside to key paths being _only_ compiler generated is that we do not get to create new ones ourselves. We only get the ones the compiler gives us.

And there are a lot of getters and setters that are not representable by key paths. For example, the “identity” key path `KeyPath<A, A>` that simply returns `self` for the getter and that setting on it leaves it unchanged. Can you think of any other interesting getters/setters that cannot be represented by key paths?
*/
// TODO
/*:
3. In our [Setters and Key Paths](https://www.pointfree.co/episodes/ep7-setters-and-key-paths) episode we showed how `map` could kinda be seen as a “setter” by saying:

“If you tell me how to transform an `A` into a `B`, I will tell you how to transform an `[A]` into a `[B]`.”

There is also a way to think of `map` as a “getter” by saying:

“If you tell me how to get a `B` out of an `A`, I will tell you how to get an `[B]` out of an `[A]`.”

Try composing `get` with free `map` function to construct getters that go even deeper into a structure.

You may want to use the data types we defined [last time](https://github.com/pointfreeco/episode-code-samples/blob/1998e897e1535a948324d590f2b53b6240662379/0007-setters-and-key-paths/Setters%20and%20Key%20Paths.playground/Contents.swift#L2-L20).
*/
// TODO
/*:
4. Repeat the above exercise by seeing how the free optional `map` can allow you to dive deeper into an optional value to extract out a part.

Key paths even give first class support for this operation. Do you know what it is?
*/
// TODO
/*:
5. Key paths aid us in getter composition for structs, but enums don't have any stored properties. Write a getter function for `Result` that plucks out a value if it exists, such that it can compose with `get`. Use this function with a value in `Result<User, String>` to return the user's name.
*/
// TODO
/*:
6. Key paths work immediately with all fields in a struct, but only work with computed properties on an enum. We saw in [Algebra Data Types](https://www.pointfree.co/episodes/ep4-algebraic-data-types) that structs and enums are really just two sides of a coin: neither one is more important or better than the other.

What would it look like to define an `EnumKeyPath<Root, Value>` type that encapsulates the idea of “getting” and “setting” cases in an enum?
*/
// TODO
/*:
7. Given a value in `EnumKeyPath<A, B>` and `EnumKeyPath<B, C>`, can you construct a value in
`EnumKeyPath<A, C>`?
*/
// TODO
/*:
8. Given a value in `EnumKeyPath<A, C>` and a value in `EnumKeyPath<B, C>`, can you construct a value in `EnumKeyPath<Either<A, B>, C>`?
*/
// TODO
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='macos'>
<timeline fileName='timeline.xctimeline'/>
</playground>
<playground version='6.0' target-platform='macos' display-mode='rendered'>
<pages>
<page name='01-Episode'/>
<page name='02-Exercises'/>
</pages>
</playground>

0 comments on commit 5c16053

Please sign in to comment.