@@ -76,24 +76,106 @@ export const message = (e: Optional<string>): string =>
7676 ( s ) => "The value was " + s
7777 ) ;
7878
79- // TODO:
79+ // TODO: Implement a function using fold, that takes an Optional<number>. If it's some, double it. If it's none, return 0;
8080
81+ // TODO: Implement a function that takes an Optional<T> for any type T. Return true if it's some, and false if it's none.
82+ const trueIfSome = < T > ( x : T ) : Optional < T > => {
83+ throw new Error ( "TODO" ) ;
84+ }
85+
86+ /*
87+ The last function you implemented is already part of the Optional type, and is called isSome().
88+ There's a corresponding isNone().
8189
90+ In some VERY LIMITED SITUATIONS you can use isSome() and then the UNSAFE getOrDie() function.
91+ It's acceptible to do this in tests, or where nested folding is incredibly cumbersome.
92+ */
8293
94+ export const unsafeStuff = ( e : Optional < string > ) : void => {
95+ if ( e . isSome ( ) ) {
96+ console . log ( e . getOrDie ( ) ) ; // AVOID
97+ }
98+ }
8399
84100/*
85- Aside: Constructing and Destructing
101+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
102+ +
103+ + Aside: But you said we used "static" functions, not methods on objects!
104+ +
105+ + Yeah, mostly we do. But Optional is from a time before we pushed that concept very hard.
106+ + At some point, we intend to replace Optional's API with something fully static.
107+ +
108+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
109+
110+
111+ A common way to handle an Optional value is to provide a default value if in the case of none.
112+
113+ You can do this with fold, but getOrElse is a shortcut.
114+ */
86115
87- Many developers are familiar with the idea of a "constructor". You pass values into a constructor
88- to construct an object. While we're not using TypeScript classes here, the functions "some" and
89- "none" are still considered the constructors for the data type.
116+ // TODO: Using getOrElse, take an Optional<{age: string}> and turn it into an {age: string}, using a default value of 0.
90117
91- What if you want to take an object and get its fields? Well, that's called "destruction". We're
92- taking an object and destructing it into its constituent parts. You'll also find "destructuring assignment"
93- as a feature of many languages, including TypeScript.
118+ // TODO: Write the same function using fold
94119
95- Our "fold" function destructures the Option type. In category theory, "fold" is known as a "catamorphism".
96120
121+ /*
122+ Another way of thinking about an Optional, is that it's an array that contains either 0 or 1 elements.
123+
124+ Let's explore this by converting Optionals to and from Arrays.
97125 */
98126
99- // TODO: head over to Exercise3OptionTest to write some test cases for the above.
127+ // TODO: Write a function that converts an Optional<A> to an A[] for any type A.
128+
129+ // TODO: Write a function that converts an A[] to an Optional<A>. If the array has more than one element, only consider the first element.
130+
131+
132+ /*
133+ Well done! You've tackled the basis of Optionals. We'll dig into them a bit more in future exercises,
134+ but everything builds on what we've done here.
135+
136+ TODO: head over to Exercise3OptionTest to write some test cases for the above.
137+
138+
139+
140+ Below are some explanatory notes on some more advanced topics. Feel free to skip them if you're still learning.
141+
142+
143+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
144+ +
145+ + Aside: TypeScript type refinement
146+ +
147+ + Why can't we use type refinement to turn an Optional<T> to a Some<T> and make getOrDie() safe?
148+ + It's to do with how we encode Optional. We use Church Encoding, so Optional is defined like this:
149+ + interface Optional<A> {
150+ + fold: <B> (ifNone: () => B, ifSome: (a: A) => B)
151+ + }
152+ +
153+ + whereas TypeScript encourages you to encode union types like this:
154+ +
155+ + type None<A> = { kind: 'none' };
156+ + type Some<A> = { kind: 'some', value: A };
157+ + type Optional<A> = Some<A> | None<A>
158+ +
159+ + Our Optional implementation predates TypeScript, so this wasn't an option at the time.
160+ + That's not to say Church Encoding is bad. There are pros and cons, but that's a story for another day.
161+ +
162+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
163+
164+
165+
166+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
167+ +
168+ + Aside: Constructing and Destructing
169+ +
170+ + Many developers are familiar with the idea of a "constructor". You pass values into a constructor
171+ + to construct an object. While we're not using TypeScript classes here, the functions "some" and
172+ + "none" are still considered the constructors for the data type.
173+ +
174+ + What if you want to take an object and get its fields? Well, that's called "destruction". We're
175+ + taking an object and destructing it into its constituent parts. You'll also find "destructuring assignment"
176+ + as a feature of many languages, including TypeScript.
177+ +
178+ + Our "fold" function destructures the Option type. In category theory, "fold" is known as a "catamorphism".
179+ +
180+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
181+ */
0 commit comments