@@ -16,6 +16,7 @@ The example list is:
16
16
* <<optionBind, Option bind>>
17
17
* <<optionFilter, Option filter>>
18
18
* <<optionMap, Option map>>
19
+ * <<ioWalkthrough, IO Walkthrough>>
19
20
20
21
== Array Exists [[arrayExists]]
21
22
@@ -258,3 +259,82 @@ public final class Option_map {
258
259
}
259
260
----
260
261
262
+
263
+ == IO Walkthrough [[ioWalkthrough]]
264
+ https://github.com/functionaljava/functionaljava/blob/master/demo/src/main/java/fj/demo/IOWalkthrough.java[Github Source]
265
+
266
+ Demonstrates how to work with the IO type.
267
+
268
+ [source,java]
269
+ ----
270
+ // IO is just a container to defer a computation (lazy), with the intention
271
+ // to encapsulate computations that either consume and/or produce side-effects
272
+ // the computation is not (yet) executed on creation hence it can be treated
273
+ // like a value
274
+
275
+ final IO<Unit> askName = () -> {
276
+ System.out.println("Hi, what's your name?");
277
+ return Unit.unit();
278
+ };
279
+
280
+ // fj.data.IOFunctions contains a lot of convenience functions regarding IO, the
281
+ // above example could be rewritten with IOFunctions.stdoutPrintln
282
+ // we now create an IO value to prompt for the name if executed
283
+
284
+ IO<Unit> promptName = IOFunctions.stdoutPrint("Name: ");
285
+
286
+ // we can compose these two values with fj.data.IOFunctions.append, since they
287
+ // both are not interested in any runtime value
288
+
289
+ IO<Unit> askAndPromptName = IOFunctions.append(askName, promptName);
290
+
291
+ // now we create an IO value to read a line from stdin
292
+
293
+ final IO<String> readName = () -> new BufferedReader(new InputStreamReader(System.in)).readLine();
294
+
295
+ // this is the same as IOFunctions.stdinReadLine()
296
+
297
+ // now we create a function which takes a string, upper cases it and creates
298
+ // an IO value that would print the upper cased string if executed
299
+
300
+ final F<String, IO<Unit>> upperCaseAndPrint = F1Functions.<String, IO<Unit>, String>o(IOFunctions::stdoutPrintln).f(String::toUpperCase);
301
+
302
+ // we now want to compose reading the name with printing it, for that we need to
303
+ // have access to the runtime value that is returned when the
304
+ // IO value for read is executed, hence we use fj.data.IOFunctions.bind instead
305
+ // of fj.data.IOFunctions.append
306
+
307
+ final IO<Unit> readAndPrintUpperCasedName = IOFunctions.bind(readName, upperCaseAndPrint);
308
+
309
+ // so append is really just a specialised form of bind, ignoring the runtime
310
+ // value of the IO execution that was composed before us
311
+
312
+ final IO<Unit> program = IOFunctions.bind(askAndPromptName, ignored -> readAndPrintUpperCasedName);
313
+
314
+ // this is the same as writing IOFunctions.append(askAndPromptName, readAndPrintUpperCasedName)
315
+
316
+ // we have recorded the entire program, but have not run anything yet
317
+ // now we get to the small dirty part at the end of our program where we actually
318
+ // execute it
319
+
320
+ // we can either choose to just call program.run(), which allows the execution to escape
321
+ // or we use safe to receive an fj.data.Either with the potential exception on the
322
+ // left side
323
+
324
+ toSafeValidation(program).run().on((IOException e) -> { e.printStackTrace(); return Unit.unit(); });
325
+
326
+ // doing function composition like this can be quite cumbersome, since you will end
327
+ // up nesting parenthesis unless you flatten it out by
328
+ // assigning the functions to variables like above, but you can use the fj.F1W
329
+ // syntax wrapper for composing single-argument functions and fj.data.IOW
330
+ // for composing IO values instead, the entire program can be written like so:
331
+
332
+ IOW.lift(stdoutPrintln("What's your name again?"))
333
+ .append(stdoutPrint("Name: "))
334
+ .append(stdinReadLine())
335
+ .bind(F1W.lift((String s) -> s.toUpperCase())
336
+ .andThen(IOFunctions::stdoutPrintln))
337
+ .safe().run().on((IOException e) -> { e.printStackTrace(); return Unit.unit(); });
338
+ ----
339
+
340
+
0 commit comments