remove "in progress" on Juli8
[lambda.git] / juli8.mdwn
1 [[!toc]]
2
3 ## What are the Juli8 Libraries? ##
4
5 In addition to the fine programming language Kapulet, which doesn't yet exist in a form you can actually execute --- though the full-featured interpreter we provided [[a week or so ago|/topics/week7_untyped_evaluator]] is a good start --- I decided it would be useful to have a collection of basic libraries for our teaching (and other) purposes, that brought OCaml, Haskell, and the Scheme implementations we recommend, more onto even footing. Of course there are fundamental differences between these languages, such as the lack of types in Scheme (though both Racket and Chicken have some facility for working with types in extensions), or the default lazy evaluation strategy in Haskell. But there are also many simply accidental differences between the languages too, in that this one provides a library function doing so-and-so, but the other one doesn't, or calls it by a different name. The Juli8 collection of libraries is aimed to reduce these differences, to make it easier to move back and forth between the languages, and also to just make some of the languages generally easier to use (from my perspective). Juli8 will eventually have components that you can install into each of Haskell, OCaml, Racket, and Chicken. For the moment, OCaml is the most developed of these, and Haskell a bit, with the Scheme components deferred for another time.
6
7 Juli8 tries to give OCaml more-or-less the same functionality that you have in Haskell's `Data.Maybe`, `Data.List`, and `Control.Monad` libraries, as well as a few others. It doesn't try for an exact match, and it doesn't strictly use the same names as Haskell does. I've aimed to at least stay close to the existing OCaml naming patterns, and also the Scheme naming patterns when they are salient to me.
8
9 Below, we'll give instructions on how to install Juli8 into your existing OCaml and/or Haskell setups. We'll also discuss how to use the non-monadic parts of the Juli8 libraries for OCaml. We discuss how to use the monadic parts of the Juli8 libraries for OCaml [[elsewhere|/topics/week9_using_the_monad_library]]. We'll also say a little bit about the little bit that Juli8 provides for you if you're using Haskell.
10
11 ## Setting up OCaml in general, and for use with Juli8 ##
12
13 1. In our instructions for installing OCaml, some of the strategies involved installing the OPAM package manager. (This doesn't appear to be available for Windows.) If you did install OPAM, then we recommend typing the following commands inside a terminal session (that is, *not* inside an OCaml session, but inside the prompt where you'd start OCaml by typing `ocaml`).
14
15         opam update
16         opam upgrade
17         opam install delimcc
18
19     We'll comment on the `delimcc` package in a moment.
20
21     We also recommend upgrading to one of the more recent versions of OCaml. This gets you the most recent stable release:
22
23         opam switch 4.02.1 && opam install --switch=4.02.1 delimcc && eval `opam config env`
24
25     This will get you a slightly older release, which however has "improved type error messages":
26
27         opam switch 4.02.0+improved-errors && opam install --switch=4.02.0+improved-errors delimcc && eval `opam config env`
28
29     Installing the `delimcc` library gives you Oleg's Delimited Continuation library for OCaml, which we will encourage you to play around with later in the term. It's not essential to have it, though. There are some advantages to using one of the 4.02.x versions of OCaml, though, rather than the 4.01.0 version I think most of us ended up installing. One advantage is that now you can use the special <code>#show <i>symbol</i></code> command in OCaml sessions, which works like Haskell's special <code>:info <i>symbol</i></code> inside a GHCi session. Then for example, instead of having to type:
30
31         module type SOMETHING = Monad.OPTION
32
33     as [[I directed you elsewhere|/topics/week9_using_the_monad_library]], you can instead just type:
34
35         #show Monad.OPTION
36
37 2. The program that starts up when you type `ocaml` is OCaml's Standard "Toplevel" Interactive Interpreter. There's an alternative interactive interpreter that you can try out, which some people like. It's called **utop** and [you can read about it here](https://github.com/diml/utop) or [here](https://opam.ocaml.org/blog/about-utop). To install it, you can just type `opam install utop`. I'm not so crazy about it myself. But I prefer to use *some* kind of helper program with OCaml's Standard Toplevel, because the Standard Toplevel itself doesn't let you scroll back through commands you typed previously, has only very rudimentary facilities for editing a line if you made a mistake and so on. One virtue of utop is that it does those things better, but there are also other ways to do them better. What I use is a wrapper program called **rlwrap**. Here are instructions for how to install that:
38
39     > First, I had to upgrade the version of the "GNU readline" library on my computer. My Mac with System 10.9.5 has a version of that library, but it's too old to use with recent versions of `rlwrap`. So I downloaded [the source code for GNU readline](http://ftp.gnu.org/gnu/readline/readline-6.3.tar.gz). Double click the downloaded archive to expand it, if your browser doesn't do that automatically. Then go inside the `readline-6.3` folder in a Terminal. On a Mac, you can click on the folder in the Finder and do a Copy (or cmd-C). Then open a Terminal and type `cd` followed by a space then do a Paste (cmd-V). Then press <code><i>return</i></code>. Once you're inside the `readline-6.3` folder, type this command in the Terminal:
40
41     >     ./configure --prefix=$HOME && make && make install
42
43     > That should build and install the readline library in your local user directories. It will take a couple of minutes. Next, download [the source code for rlwrap](http://utopia.knoware.nl/~hlub/rlwrap/rlwrap-0.42.tar.gz). Double-click to expand and go inside the `rlwrap-0.42` folder in a Terminal, as before. Then type this command in the Terminal:
44
45     >     ./configure --prefix=$HOME && make CFLAGS="-g -O2 \
46     >       -I $HOME/include -L $HOME/lib" && make install
47
48     If that all completes without errors, then you have gotten `rlwrap` installed. Congratulations. To use it, you just will now type `rlwrap ocaml ...` wherever before you would ordinarily type `ocaml ...` This is just to make interactive OCaml sessions nicer. To compile code with `ocamlc ...` and so on, you don't use `rlwrap` for that. (If you see error messages of the form `-bash: rlwrap: command not found`, then you should make sure that you have a `.bash_profile` or `.bashrc` in your `$HOME` directory which has a line containing something like `export PATH="$HOME/bin:$HOME/Library/Haskell/bin:$PATH"`. Then maybe start up a new Terminal.)
49
50     Some keycommands you can now use are:
51
52     * `^H` (that is, Control+`H`) will delete one char to the left of the cursor position (also `backspace`)
53     * `^D` will delete one char to the right of the cursor position (but if you type it on a blank line it will quit the program you're running)
54     * `^W` will delete one word to the left of the cursor position (also `esc` followed by `backspace`, after releasing `esc`)
55     * `esc` + `D` will delete one word to the right of the cursor position
56     * `^U` will delete from the cursor position leftwards all the way to the start of the line
57     * `^K` will delete from the cursor position rightwards all the way to the end of the line
58     * Control+`-` will undo one editing command or sequence of typed characters
59     * `esc` + `R` will (usually) erase the whole line (undoing everything)
60     * `^A` moves the cursor to the start of the line
61     * `^E` moves the cursor to the end of the line
62     * `^B` and `^F` work like left and right arrows
63     * `esc` + `B` and `esc` + `F` move left and right a whole word at a time (on the Mac, Option-`left` and Option-`right` do the same)
64     * Control-`]`+`x` will move the cursor rightwards to the next `x` character on the line (similarly for other characters in place of `x`). You can do the same leftwards by typing `esc`+Control-`]`+`x`. You can move to the second-next `x` character by typing `esc`+`2`+Control-`]`+`x`. This is all pretty cumbersome.
65     * `^L` clears the screen
66     * `up`/`down` arrows let you scroll through previous lines you typed (also `^P` / `^N`)
67     * `^R` lets you search through previous lines you typed for a matching substring; to refine the search keep making the substring longer, or type `^R` again to find an earlier match. Type `esc` to exit the search and edit the currently showing command line. Type `^G` to exit the search with a blank command line.
68
69     If you create a file named `$HOME/.inputrc` with the contents:
70
71         set blink-matching-paren on
72
73     then you will get the further nice feature that when you type a close parenthesis, `rlwrap` will temporarily make the cursor jump to the matching open parenthesis, so that you can see how many close parentheses you need to type. If you want to further customize `rlwrap` or the above keycommands, you can read the documentation at `man rlwrap` and `man readline`, and also look into the Preferences of your Terminal program. (On the Mac, look under Terminal menu/Preferences/Keyboard tab.) This gets complicated quickly, but those are the places to start looking if you want to experiment. You should of course also read around on the web, rather than just changing these blindly.
74
75 3. Whether you use `utop` or `rlwrap ocaml` or just plain `ocaml`, you will need to set up some initialization commands in order to use the Juli8 libraries. You'll want to edit or create an file called `.ocamlinit` in your `$HOME` directory. The file may already be there and have some commands in it if you used OPAM.
76
77     After any commands that are already there, add these lines:
78
79         #load "str.cma";;
80         module Std = struct
81           include Pervasives
82           module List = List
83           module Random = Random
84           module String = String
85         end
86
87         #directory "+../delimcc";;
88
89         (* you'll have to substitute your own $HOME directory in for `/Users/jim/` *)
90         #directory "/Users/jim/.juli8/ocaml";;
91
92         #use "juli8.ml";;
93
94 4. Next create a folder in your `$HOME` directory named `.juli8`. Download the Juli8 code from [[here|/code/Juli8-v1.2.tgz]]. That link will no doubt be updated frequently in April and May 2015. The current version is: 1.2, posted 4 April 2015. Copy the contents of the `Juli8` folder that you downloaded into the `$HOME/.juli8` folder that you created.
95
96     Now whenever you start up OCaml, the Juli8 OCaml libraries (including their monad components, which we'll be making extensive use of) will automatically be loaded. <!-- If later you want to load Oleg's Delimcc library, type `#load "delimcc.cma";;` then use the `Delimcc` module. -->
97
98
99 ## Using the Juli8 libraries with OCaml ##
100
101 Here is an overview of what you get in the non-monadic parts of the Juli8 library for OCaml. For the monadic part, [[see here|/topics/week9_using_the_monad_library]].
102
103 First, at the top level of your session --- that is, not inside any module --- you get functions `ident` and `%` that work like Haskell's `id` and `.`. That is, `f % g` is equivalent to `fun x -> f (g x)`.
104
105 You also get the functions `const`, `flip`, `fix`, `swap`, `curry`, `uncurry`, `even`, and `odd` that work like their Haskell counterparts. <!-- Data.function.fix, Data.Tuple.swap -->
106
107 These functions have Haskell counterparts with slightly different names: OCaml's `pair` is Haskell's `(,)`; OCaml's `sign` is Haskell's `signum`; OCaml's `pow (x : int) (n : int)` is Haskell's `x^n`; OCaml's `ignore(expr1); expr2` is like `let _ = expr1 in expr2` in Haskell (and also in OCaml).
108
109 Note that OCaml already came with the following functions that work like their Haskell counterparts: `max`, `min`, `not`, `&&`, `||`, `succ`, `abs`, `fst`, and `snd`. OCaml's infix operators `mod` and `/` work like Haskell's `rem` and `quot`, not like Haskell's `mod` and `div`. (These behave the same when both arguments are positive.)
110
111 Juli8 gives you a version of `pred` that replaces the default OCaml `pred`, and raises an error if you say `pred 0`. There's also a more tolerant variant, `pred'`, where `pred' 0` is simply `0`. If you want the standard OCaml `pred`, use `Std.pred x` or just `x-1`.
112
113 Corresponding to `pred` and `pred'`, there are also `sub` and `sub'`, where `sub 8 10` raises an error but `sub' 8 10` is simply `0`.
114
115 Here are some functions in OCaml/Juli8 but not in Haskell: `mid x y` finds the integer midway between `x` and `y` without overflowing; `mapfst f (x, y)` is `(f x, y)`; `mapsnd g (x, y)` is `(x, g y)`; `non f` is `fun x -> not (f x)`; `non2 f` is `fun x y -> not (f x y)`.
116
117 Haskell has a function `iterate` that makes infinite lists. It's possible to make infinite (lazy) lists in OCaml, but modestly complex, and this isn't now provided by Juli8. Instead, Juli8 has a function `iterate n s z` that returns what would be the `n`th member of the infinite Haskell list `iterate s z`, that is, the `n`-fold composition of `s` applied to `z`.
118
119 OCaml/Juli8 also has a function `iter_while p s z`, which keeps applying `s` to `z` until the result no longer satisfies the predicate `p`. This is like the Haskell command `until (not . p) s z`.
120
121 OCaml/Juli8 has a command `forever f x` which keeps applying `f` to argument `x` forever. That is, it does `let _ = f x in let _ = f x in ...`. Not `f (f (... z))`. Haskell has a similar command, but it only applies to Monads, and Haskell's version doesn't involve `x`. That is, Haskell does `mm >> mm >> ...` for some monadic value `mm`.
122
123 OCaml/Juli8 also has `factorial` and `choose n k` functions. But unlike Haskell, it doesn't (yet) have `gcd` or `lcm` functions.
124
125 Haskell's ways of handling printing is rather different from OCaml's and most other languages. But if you've learned any Haskell, you've already probably become familiar with this.
126
127 OCaml and Haskell's ways of handling errors is also somewhat different. OCaml has:
128
129 <pre>
130 raise <i>&lt;exception&gt;</i>
131 failwith "msg"  (* same as `raise (Failure "msg")` *)
132 invalid_arg "msg"  (* same as `raise (Invalid_argument "msg")` *)
133 undefined ()  (* provided by Juli8 *)
134 assert <i>&lt;bool&gt;</i> : unit
135 </pre>
136
137 Corresponding are the following operations in Haskell:
138
139 <pre>
140 Prelude.error "msg"
141 Prelude.undefined
142 Control.Exception.assert <i>&lt;bool&gt; &lt;anything&gt;</i>
143 </pre>
144
145 <!--
146 OCaml:
147   exit <int>
148
149 Haskell:
150   System.Exit.exitFailure :: IO a
151   System.Exit.exitSuccess :: IO a
152
153
154 Control.Exception.throw :: Exception -> a
155 Control.Exception.throwIO :: Exception -> IO a
156 Control.Exception.ioError (System.IO.userError "msg") :: IO a
157
158 OCaml:
159   try body with ExceptionPattern1 -> ... | ExceptionPattern2 -> ...
160 From version 4.02, OCaml also has:
161   match expr with Pattern1 -> ... | exception ExceptionPattern1 -> ... | ...
162
163 Haskell:
164   Control.Exception.evaluate : a -> IO a
165   Control.Exception.catch (body :: IO a) (\exn -> (handler :: IO a))
166   Control.Exception.catches (body :: IO a) [Handler (\exn -> handler), ...]
167   Control.Exception.try (body :: IO a) :: IO (Either e a) -- returns an `Either e a` if it can, but if a non-type-`e` error was thrown, propagates it
168
169 OCaml/Juli8:
170   [[finally]] TODO
171
172 Haskell:
173   Control.Exception.finally (body :: IO a) (final :: IO b) :: IO a
174   Control.Exception.onException (body :: IO a) (final :: IO b) :: IO a -- here finalizer is skipped on clean exit
175
176 OCaml ref cells:
177   `==` and `!=`
178   `ref x` creates a new ref cell
179   `!cell` gets the contents of a ref cell
180   `cell := x'` modifies the contents of a ref cell
181   `incr cell` and `decr cell` modify the contents of a ref cell that holds an `int`
182
183 Does Haskell have ref cells, you ask? Well it has `STRef`s and `IORef`s, these are pretty similar in functionality to OCaml's reference cells. If you're willing to use the Haskell function `unsafePerformIO`, you can make them more-or-less exactly the same. (Though you will then lose some of the guarantees that Haskell's type system aims to provide.) Maybe we'll write a page somewhere explaining how to get the most OCaml-like behavior out of Haskell. We won't do that here and now.
184 -->
185
186 ### Option ###
187
188 Juli8 provides an `Option` module (this same module can also be found at `Monad.Option`). This provides a number of functions that you can see by typing `#show Monad.Option` if you're running OCaml version 4.02 or above. For earlier versions of OCaml, type `module Something = Option;;` to see the same result. A few of the functions from the `Option` module are also currently exported to be available at the top level. Thus you can simply say `is_some x` instead of `Option.is_some x`. But if you're not sure which are available in this way, just play it safe and use the preferatory `Option.`.
189
190 ### List ###
191
192 Juli8 provides a `List` module that can also be found at `Monad.List`, and that replaces the standard OCaml `List` module, which is a bit skimpy. The official `List` module is still available at `Std.List`, but all of its functionality is present in Juli8's `List` module, albeit sometimes under slightly different names. To see what's in the `List` module that Juli8 provides, type `#show List` in OCaml version >= 4.02. Many of the functions here parallel functions from the Haskell libraries.
193
194 As with the `Option` library, a few of the functions are also currently exported to be available at the top level.
195
196 Without trying to give an exhaustive explanation of these functions, here are a few comments.
197
198 Juli8's `head` and `tail`, like OCaml's official `List.hd` and `List.tl`, both raise an error if applied to an empty list. However, Juli8 also provides a `tail'` function that returns `[]` when applied to the empty list. (Compare `pred'`, described above.) There are analogous pairings between `take`,`drop`, and `split` on the one hand, and `take'`, `drop'`, and `split'` on the other.
199
200 Juli8 also provides a function `opthead xs` that returns either `Some x` if `xs` has a head, else `None`.
201
202 Some functions in Juli8's libraries accept OCaml's *optional labeled* arguments. Thus for example `zip xs ys` will raise an error if the lists have different lengths, but `zip ~short xs ys` will instead just stop with the shorter list. `drop_while ~rev p xs` drops elements from the *right end* of `xs` that satisfy the predicate `p`, rather than from the left end; similarly `find ~rev p xs` finds the *last* item in `xs` that satisfies the predicate. `remove ~many p xs` removes *all* the members of `xs` that satisfy predicate `p`, rather than just the first. There are many examples like this. See the comments in the source code for a full description.
203
204 A few more examples worth calling attention to are that `insert ~many x xs` inserts `x` into the appropriate position in already-sorted list `xs`, but that without the `~many` flag, `insert` won't insert items that are already present in the list. Similarly, `sort ~many xs` will sort a list, retaining arguments that compare as equal in the order they originally appeared, but without the `~many` flag, `sort` will drop all duplicates after the first.
205
206
207 ### String ###
208
209 Juli8 provides a `String` module that replaces the standard OCaml `String` module, and includes some (but not all) functionality from the standard `String`, `Str`, and `Char` modules. The official `String` module can be found at `Std.String`. To see what's in the `String` module that Juli8 provides, type `#show String` in OCaml version >= 4.02. Some of the functions here parallel functions from the Haskell libraries.
210
211 ### Random ###
212
213 Juli8 provides a `Random` module that replaces the standard OCaml `Random` module, and includes some (but not all) functionality from the standard `Random` module, which can still be found at `Std.Random`. To see what's in the `Random` module that Juli8 provides, type `#show Random` in OCaml version >= 4.02.
214
215
216
217 ## Setting up Haskell for use with Juli8 ##
218
219 1. When (If) you installed Haskell, we hope you did it via a method that gave you the Haskell Platform. This will give you a recent version of the Glasgow Haskell Compiler (GHC), which comes with the interactive Haskell session program `ghci`, along with the **Cabal** package manager (the analogue of OCaml's OPAM) and also with a collection of the most widely-used libraries in the Haskell community, that don't come along with GHC itself.
220
221 2. Assuming you do have Cabal, we recommend you do the following. First, find out where Cabal installs logs of its activity. On my Mac, it logs them in the file `~/Library/Haskell/logs/world`. Now what I did was to type the following command in a Terminal:
222
223         ln -s ~/Library/Haskell/logs/world ~/.cabal/
224
225     Now I can find a link to what Cabal has done inside Cabal's own folder, without needing to remember or hunt down where the hell on my disk that information has been stored. (All right, to be honest, you can skip this whole step if you want. But I recommend doing it.)
226
227 3. Still assuming you have Cabal, type the following in a Terminal:
228
229         cabal update
230         cabal install --user cabal-install ghc-paths semigroups hoogle
231
232     <!-- also haskell-docs for :whatis command, but I'm not sure yet this is worth it. -->
233
234 4. If you haven't already downloaded and installed the Juli8 libraries as described in Step 4 under the earlier OCaml section, do that now. Also type the following lines in a Terminal:
235
236         ln -s ~/.juli8/haskell ~/.ghc/juli8
237
238 5. Check to see whether any of the following files exist on your system. `$HOME` will be some directory like `/Users/jim` or `/home/jim` or `C:/Documents\ and\ Settings/jim`:
239
240     * `$HOME/.ghci`
241     * `$HOME/.ghc/ghci.conf`
242     * `$HOME/"Application Data"/ghc/ghci.conf`
243
244     If you find such a file, you will add lines to it in the next step. If you don't find such a file, create one.
245
246 6. Add these lines to the `.ghci` or `ghci.conf` file identified in the previous step:
247
248         -- reads ghci commands from any file named in $GHCIRC
249         :cmd (System.Environment.getEnvironment >>= maybe (return "") readFile . lookup "GHCIRC")
250
251         -- special :commands from Juli8
252         :{
253         :cmd do { dot_ghc <- System.Directory.getAppUserDataDirectory "ghc";
254                   let { juli8 = dot_ghc ++ "/juli8";
255                         cmds = juli8 ++ "/commands" };
256                   juli8_exists <- System.Directory.doesDirectoryExist juli8;
257                   cmds_exists <- System.Directory.doesFileExist cmds;
258                   Control.Monad.when cmds_exists $ putStrLn "Loading juli8/commands ...";
259                   return $ unlines $ if cmds_exists then [":set -i"++juli8, ":script "++cmds] else if juli8_exists then [":set -i"++juli8] else [] }
260         :}
261
262         :def! url (\l->return $ ":!open "++l)
263         -- :set editor vim
264         -- :set +m -- for multiline input
265         -- :set +t -- to print types after each binding
266
267         :load Juli8
268         :mod Juli8
269
270     You may want to uncomment the `:set editor vim` line, but only if you know how to use the text editor `vim`. Other text editors you may be familiar with, and can use here are:
271
272         :set editor emacs
273         :set editor nano
274         :set editor open -a TextEdit -- Mac-only
275         :set editor bbedit -- Mac-only, see http://www.barebones.com/support/bbedit/cmd-line-tools.html
276         :set editor mate -- Mac-only, see http://manual.macromates.com/en/using_textmate_from_terminal.html
277         -- for Windows, use one of https://wiki.haskell.org/Windows#Editors
278
279     You may want to uncomment the `:set +m` line. What this does is let you type multi-line commands in the `ghci` sessions. There is a different way to do that, where you type like this:
280
281         :{
282         multiline
283           command
284         :}
285
286     but that's pretty cumbersome. The downside of having `:set +m` on is that sometimes you'll have to type an extra blank line before `ghci` will respond to your input.
287
288 If everything works, then when you start up GHCi, you should see a prompt like this:
289
290     Prelude Juli8>
291
292 Note that the GHCi command line already by default accepts the special keycommands described under item 2 in the Setting up OCaml section above. Additionally, if you type just the start of a command and then press `Tab`, GHCi will attempt to figure out what you started to type and finish the word for you.
293
294
295 ## What do I get from Juli8 for Haskell? ##
296
297 There are two or three benefits that Juli8 provides for Haskell, and they're not a big deal. If you're already a seasoned Haskell user, you may or may not find them helpful.
298
299 First, Juli8 comes with a bunch of extra `:commands` to use at the GHCi prompt. You can see a list of what it installs by typing `:?`. Some of the commands listed in `:?` were already present before Juli8 arrived, and are just here collected and explained in a way I find more helpful. Others are provided by Juli8 itself. Many of these are based on commands already published elsewhere on Haskell wikis and so on, so you may have installed some versions of them already yourself. I'll leave it to you to pick and choose whether anything that comes with Juli8 suits your further needs.
300
301 I developed these `:commands` on a Mac, and expect that some of the assumptions I made won't work on other systems. As the library matures, we'll try to make it work for a broader range of systems, or give specific instructions about how to customize it.
302
303 The command `:help` will give you the old, official help text, that doesn't show the extra commands installed by Juli8.
304
305 Second, Juli8 comes with a module/library that collects together a number of elements from scattered other locations in the Haskell libraries. These include the `Semigroup` libraries you installed in Step 3 of the above instructions, which you should use in place of Haskell's standard `Data.Monoid` libraries. Note that the `Semigroup` library provides `First a` and `Last a` types that differ from the types of the same name in `Data.Monoid`. Juli8 also provides `OptFirst a` and `OptLast a` types that behave more like the `First a` and `Last a` types from `Data.Monoid`. It also provides analogous types `OptMax a` and `OptMin a`. (If you don't know what any of this means, don't worry about it.)
306
307 Third, Juli8 comes with a module/library `IOPlus` that isn't loaded by default, but which you can load manually by saying `:add IOPlus`. This provides instances to make `IO a` a `Monoid` when `a` is, and to make `IO` act like an instance of the `Alternative` and `MonadPlus` typeclasses. This has some limitations, and can't be done perfectly, which is why it isn't done in the standard libraries. There's also an `IOFirst` and an `IOLast`. This is more experimental than the rest of the stuff in Juli8 and may well change or be removed. I'll explain it and refine it another time.
308