<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Philip: music, code and stuff.</title>
    <link>https://filib.io</link>
    <description>Philip is a senior software engineer working across AI, security and music technology.</description>
    <pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate>
    <item>
      <title>Notes on a 1987 Sampler&#39;s Firmware</title>
      <link>https://filib.io/posts/2026-05-31-notes-on-a-1987-samplers-firmware.html</link>
      <description>&lt;article class=&#34;post&#34;&gt;&#xA;  &lt;h1&gt;Notes on a 1987 Sampler&amp;#39;s Firmware&lt;/h1&gt;&#xA;  &lt;header class=&#34;post-meta&#34;&gt;&#xA;    &lt;span class=&#34;post-date&#34;&gt;2026-05-31&lt;/span&gt;&#xA;    &lt;span class=&#34;post-tags&#34;&gt;&lt;a href=&#34;/tags/casio.html&#34; class=&#34;post-category green&#34;&gt;casio&lt;/a&gt; &lt;a href=&#34;/tags/music.html&#34; class=&#34;post-category green&#34;&gt;music&lt;/a&gt; &lt;a href=&#34;/tags/ai.html&#34; class=&#34;post-category green&#34;&gt;ai&lt;/a&gt;&lt;/span&gt;&#xA;  &lt;/header&gt;&#xA;  &lt;div class=&#34;post-body&#34;&gt;&#xA;    &lt;p&gt;The Casio FZ-1&#39;s firmware is 64 KiB of V50 machine code, masked into two 32 KiB ROMs. It runs the keyboard, the LCD, the floppy drive, and an eight-voice sound engine scheduled on a single timer interrupt. I have been reverse engineering it. I had never tried it before this. It turns out I really enjoy it.&lt;/p&gt;&#xA;&lt;p&gt;Reverse engineering involves taking compiled bytes back to something you can read and reason about. There is no source code, no comments, no symbol table; just instructions, addresses, and the side effects they cause.&lt;/p&gt;&#xA;&lt;p&gt;I downloaded &lt;a href=&#34;https://github.com/NationalSecurityAgency/ghidra&#34;&gt;Ghidra&lt;/a&gt;, the disassembler the NSA open-sourced in 2019. You open a binary and it gives you an instruction listing, a decompiled C view that approximates the original, and a graph of which functions call which.&lt;/p&gt;&#xA;&lt;p&gt;The first thing the disassembler told me was nonsense. The reason was that the FZ-1&#39;s ROM lives on two physical chips wired so one provides the low byte and the other the high byte of every 16-bit word the CPU fetches; neither half makes sense on its own. The two have to be zipped together first. These are the last 16 bytes of the merged image:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;fz1s.bin (even bytes):  EA 06 F0 49 4F 55 49 ...&#xA;fz2s.bin  (odd bytes):  50 00 48 52 59 4B FF ...&#xA;interleaved:            EA 50 06 00 F0 48 49 52 4F 59 55 4B 49 ...&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The first five bytes shown, &lt;code&gt;EA 50 06 00 F0&lt;/code&gt;, decode as &lt;code&gt;JMP FAR F000:0650&lt;/code&gt;: the reset vector. They sit at the very top of the address space, which is where 8086-family CPUs boot from. The next eight, &lt;code&gt;48 49 52 4F 59 55 4B 49&lt;/code&gt;, spell HIROYUKI. Apparently the firmware engineer&#39;s name. Nobody seems to have confirmed publicly who he was; the same signature was spotted on a &lt;a href=&#34;https://gearspace.com/board/electronic-music-instruments-and-electronic-music-production/926789-casio-fz1-questions-6.html&#34;&gt;Gearspace thread&lt;/a&gt; years ago and the trail goes cold there too. Someone else figured the interleave out on that thread; I rediscovered it independently and we both ended up staring at the same name.&lt;/p&gt;&#xA;&lt;p&gt;The first stretch of work was hand-rolled. I built a small pipeline that fed the model pre-decoded instruction windows for one function at a time, with whatever annotation I already had for context. The model proposed an explanation. A separate gate then re-read the same bytes out of the ROM image and rejected any claim whose cited bytes did not match what was actually there. I ran this in batches, eight functions at a time, until every callable routine in the firmware had at least a one-line summary tied to specific instructions.&lt;/p&gt;&#xA;&lt;p&gt;Then I switched to &lt;a href=&#34;https://github.com/bethington/ghidra-mcp&#34;&gt;ghidra-mcp&lt;/a&gt;, which exposes Ghidra&#39;s API to a model directly. Instead of feeding it pre-decoded windows, the model could ask Ghidra to decompile a function on demand, list its callers, follow a cross-reference, write its annotations back into the Ghidra project rather than into a sidecar file. The C the model produced was closer to what the original probably looked like, and it was easier to spot where the model was confabulating versus where it was reading the bytes, because the bytes were one query away. Or more honestly: more than once the model wrote a plausible-sounding paragraph that the gate then rejected because the citations did not survive contact with the ROM.&lt;/p&gt;&#xA;&lt;p&gt;What I keep coming back to about the firmware itself is how often one routine does the work of several. There is a routine called &lt;code&gt;work_reset&lt;/code&gt; that the firmware uses for the cold boot and for every soft mode switch; one piece of code zeroes the sound engine and fills the voice table with free markers, called from seven different sites. Every LCD drawing primitive (&lt;code&gt;pset&lt;/code&gt;, &lt;code&gt;line&lt;/code&gt;, &lt;code&gt;cls&lt;/code&gt;) takes a colour argument whose top bit, if set, suppresses the LCD write and composes into a 1-bit-per-pixel mirror in RAM instead. So &lt;code&gt;pset(x, y, color)&lt;/code&gt; flushes to the display, and &lt;code&gt;pset(x, y, color | 0x8000)&lt;/code&gt; accumulates into the mirror, which is then committed in one burst by a later call without the bit set. ORing one bit into a parameter turns immediate drawing into batched drawing. The voice allocator, when a MIDI note arrives, walks the eight voice slots up to three times: first for a free one, then for a slot already playing the same key on the same channel (replacement), then for the oldest live voice (stealing). And the data formats themselves are unified: LOAD and SAVE each go through one orchestrator that dispatches to three transports (floppy, the inter-unit data port, MIDI SysEx), with the same buffer composition and chunking. A voice saved to floppy and the same voice broadcast as MIDI SysEx are the same bytes in the same order. One engineer worked this out forty years ago on a machine with 64 KiB of code budget, and the taste is consistent from the cold boot to the LCD primitives to the voice scheduler to the way bytes leave the box.&lt;/p&gt;&#xA;&lt;p&gt;The practical reason for going to all this trouble: I needed a sharper model of what the firmware actually expects from a disk image before I could trust &lt;a href=&#34;https://github.com/philipcunningham/fizzle&#34;&gt;&lt;code&gt;fizzle&lt;/code&gt;&lt;/a&gt;&#39;s output beyond the cases I had already tested by hand, and I wanted to write small Type-5 programs (Casio&#39;s term for user-loadable binaries that run on the sampler) without each one being a fresh trial. Both of those are closer now. The disk-format work is paying off because the firmware-side reader is no longer a black box. More to come soon.&lt;/p&gt;&#xA;&lt;p&gt;Thank you, HIROYUKI.&lt;/p&gt;&#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/article&gt;&#xA;</description>
      <pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Tools for a 1987 Sampler</title>
      <link>https://filib.io/posts/2026-05-29-tools-for-a-1987-sampler.html</link>
      <description>&lt;article class=&#34;post&#34;&gt;&#xA;  &lt;h1&gt;Tools for a 1987 Sampler&lt;/h1&gt;&#xA;  &lt;header class=&#34;post-meta&#34;&gt;&#xA;    &lt;span class=&#34;post-date&#34;&gt;2026-05-29&lt;/span&gt;&#xA;    &lt;span class=&#34;post-tags&#34;&gt;&lt;a href=&#34;/tags/casio.html&#34; class=&#34;post-category green&#34;&gt;casio&lt;/a&gt; &lt;a href=&#34;/tags/music.html&#34; class=&#34;post-category green&#34;&gt;music&lt;/a&gt; &lt;a href=&#34;/tags/ai.html&#34; class=&#34;post-category green&#34;&gt;ai&lt;/a&gt;&lt;/span&gt;&#xA;  &lt;/header&gt;&#xA;  &lt;div class=&#34;post-body&#34;&gt;&#xA;    &lt;p&gt;Recently I &lt;a href=&#34;/posts/2026-05-14-notes-on-a-1987-sampler.html&#34;&gt;wrote about&lt;/a&gt; the gap between my &lt;a href=&#34;https://www.vintagesynth.com/casio/fz-1&#34;&gt;Casio FZ series&lt;/a&gt; sampler and the tools for getting samples onto it. &lt;a href=&#34;https://github.com/philipcunningham/fizzle&#34;&gt;&lt;code&gt;fizzle&lt;/code&gt;&lt;/a&gt; is what I have been making to fill it. It turns modern sample files into disk images a Casio FZ can read.&lt;/p&gt;&#xA;&lt;p&gt;A tool for this kind of job already existed, just not for the machine I cared about. &lt;a href=&#34;https://www.chickensys.com/products2/translator/&#34;&gt;Chicken Systems Translator&lt;/a&gt; converts between sampler formats, and I use it to move &lt;a href=&#34;https://sfzformat.org&#34;&gt;SFZ&lt;/a&gt; instruments onto my Akai S3000XL. The Casio FZ series is not on its list. &lt;a href=&#34;https://www.fmjsoft.com/awavestudio.html&#34;&gt;Awave Studio&lt;/a&gt; reads and writes individual FZ files but not the disk format, and only on Windows. So the samples that played on the Akai would not play on the Casio, even though the Casio is the more interesting instrument to my ears.&lt;/p&gt;&#xA;&lt;p&gt;There was another reason to do it myself. I wanted to experiment with pair programming with an AI, in this case Claude Code, and a binary format suits that well: either the disk loads on the sampler or it does not, so I always knew whether a change had worked.&lt;/p&gt;&#xA;&lt;p&gt;Go was a good fit. Cross-compiling a static binary for macOS, Linux and Windows is one command each, and most of the libraries I used are MIT licensed, so I can hand the binaries to someone else without much thought.&lt;/p&gt;&#xA;&lt;p&gt;I ran Casio&#39;s 1987 &lt;em&gt;FZ-1 Data Structures&lt;/em&gt; document through &lt;a href=&#34;https://en.wikipedia.org/wiki/Optical_character_recognition&#34;&gt;OCR&lt;/a&gt;, fed it to the model, and we wrote code against it. Then I put a disk image onto the &lt;a href=&#34;https://gotekfloppyemulator.com/&#34;&gt;Gotek floppy emulator&lt;/a&gt; in my FZ-10M and saw what the sampler made of it. Some of it matched the document. Some of it did not, and the front panel of an FZ-10M is small, with one corner of mine hard to read, so working out why was slow. Then we fixed something and went round again.&lt;/p&gt;&#xA;&lt;p&gt;For most jobs the file that matters is the &lt;code&gt;fzf&lt;/code&gt;. An &lt;code&gt;fzf&lt;/code&gt; (full dump) holds up to 64 samples with a bank mapping over the top that decides which key plays which sample, on which channel, through which output. The Casio loads one of them in a single operation, which is easier than loading voices one at a time.&lt;/p&gt;&#xA;&lt;p&gt;A big instrument does not always fit on one floppy, though, and splitting it across two was the part that gave me trouble. The FZ only has 2 MB of sample memory, so a large patch has to span two disks. My first attempt put a bank sector and voice headers on both disks, on the assumption that each disk ought to describe itself. The sampler loaded both disks, but the audio from the second disk came in with a glitch at the start that sounded like clipping. At first I assumed one of my own samples was clipping.&lt;/p&gt;&#xA;&lt;p&gt;Claude Code and I went round this for a while. Every idea it had was reasonable, and none of them were right, because the answer was not in the spec or in my code. I only worked it out by saving a two-disk set from the FZ-10M itself and reading the bytes. The second disk had no bank sector and no headers at all. It was just the leftover audio from the first disk, and disk one carried the parameters for the whole instrument, including the voices whose audio ended up on disk two. The headers I had been writing to the front of my second disk were what the sampler was playing as that glitch. Once I understood that, the fix was small. The model could work from the format I had described to it, but it could not know the one thing I had never told it, because that thing only existed in what the hardware wrote to the disk. I had to go and find it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/philipcunningham/fizzle&#34;&gt;&lt;code&gt;fizzle&lt;/code&gt;&lt;/a&gt; also goes the other way now: an SFZ instrument becomes an &lt;code&gt;fzf&lt;/code&gt;, and an &lt;code&gt;fzf&lt;/code&gt; can be taken back apart into SFZ with its WAVs, so a patch made on the hardware can come back into a DAW. Round-tripping turned out to be a good way to catch mistakes. If a file does not come back the same as it went in, something is wrong, and you notice straight away.&lt;/p&gt;&#xA;&lt;p&gt;Once it was handling real instruments, I gathered a pile of old FZ disks from around the internet and ran the lot through &lt;a href=&#34;https://github.com/philipcunningham/fizzle&#34;&gt;&lt;code&gt;fizzle&lt;/code&gt;&lt;/a&gt; at once. That found problems no single disk had shown me. The 1987 document is mostly right, but it is not the same as the disks people actually have. One field I had treated as a voice count was really a count of key splits. Most of the time those are the same number, so it never mattered; on the disks where they differ, my code fell over. Others had small corruptions that probably crept in years ago, when someone copied a floppy onto a hard drive.&lt;/p&gt;&#xA;&lt;p&gt;Working this way was good, though a few things grated. Sometimes it ignored instructions I had written down plainly: I would set a rule and watch it get broken a few messages later. More than once it tried to get a failing test to pass by quietly weakening the test instead of fixing the code, which is the last thing you want from something meant to be keeping you honest. So I learned to keep the strict checksum tests in place and to read the diffs myself rather than take its word for what it had done.&lt;/p&gt;&#xA;&lt;p&gt;It still sped the work up. A fiddly byte layout never bored it, and it was good company for the slow parts late at night. It did not save me from having to understand the problem, though. The two-disk bug is the clearest example: the answer was not written down anywhere, so it had to come from me.&lt;/p&gt;&#xA;&lt;p&gt;The samples that play on my Akai play on the Casio now too, and the FZ-10M has gone from a fussy curiosity to something I can actually load with my own sounds. There are more tools on the way, and the short video I promised last time is coming soon.&lt;/p&gt;&#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/article&gt;&#xA;</description>
      <pubDate>Fri, 29 May 2026 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Notes on a 1987 Sampler</title>
      <link>https://filib.io/posts/2026-05-14-notes-on-a-1987-sampler.html</link>
      <description>&lt;article class=&#34;post&#34;&gt;&#xA;  &lt;h1&gt;Notes on a 1987 Sampler&lt;/h1&gt;&#xA;  &lt;header class=&#34;post-meta&#34;&gt;&#xA;    &lt;span class=&#34;post-date&#34;&gt;2026-05-14&lt;/span&gt;&#xA;    &lt;span class=&#34;post-tags&#34;&gt;&lt;a href=&#34;/tags/music.html&#34; class=&#34;post-category green&#34;&gt;music&lt;/a&gt; &lt;a href=&#34;/tags/casio.html&#34; class=&#34;post-category green&#34;&gt;casio&lt;/a&gt;&lt;/span&gt;&#xA;  &lt;/header&gt;&#xA;  &lt;div class=&#34;post-body&#34;&gt;&#xA;    &lt;p&gt;The &lt;a href=&#34;https://www.vintagesynth.com/casio/fz-1&#34;&gt;Casio FZ-1&lt;/a&gt;, released in 1987, is a 16-bit sampler with eight voices, three sample rates, and a 3.5&amp;quot; floppy drive. The FZ-10M rack came with 2MB of sample memory as standard, double what the FZ-1 keyboard shipped with.&lt;/p&gt;&#xA;&lt;p&gt;You can hear an FZ-10M on &lt;a href=&#34;https://en.wikipedia.org/wiki/Frequencies_(LFO_album)&#34;&gt;LFO&#39;s Frequencies&lt;/a&gt; (Warp, 1991). Mark Bell and Gez Varley used it on the &lt;a href=&#34;https://www.youtube.com/watch?v=s-1Y2EqThyQ&#34;&gt;title track&lt;/a&gt;. Aphex Twin used one on a lot of his early records. The FZ series came out of Casio&#39;s late-eighties professional line, alongside the calculators and the &lt;a href=&#34;https://en.wikipedia.org/wiki/Casio_VL-1&#34;&gt;VL-Tone&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The samples are mono, the envelopes take a while to learn, and the filters smear the signal in a way that is hard to describe and very pleasant to hear.&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;uber weird filter architecture, dig/analog hybrid&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://web.archive.org/web/20141103131334/http://noyzelab.blogspot.co.uk/2014/11/syrobonkers-part1.html&#34;&gt;Aphex Twin, SYROBONKERS 2014&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The thing about owning an FZ in 2026 is that getting a sample onto one is its own small project. You can put a real 3.5&amp;quot; floppy through a real drive, assuming the drive still works and you can find one of the disks the firmware will read. More often you fit a &lt;a href=&#34;https://gotekfloppyemulator.com/&#34;&gt;Gotek floppy emulator&lt;/a&gt; and load &lt;code&gt;.img&lt;/code&gt; files from a USB stick. Either way you need the disk image. The disk format is from 1987 and has not had a lot of attention in 2026&#39;s tooling landscape. There is a primary document somewhere in a forum thread, there is a sampler in my rack, and not much tooling that bridges the two.&lt;/p&gt;&#xA;&lt;p&gt;Some tooling does exist for the file format. &lt;a href=&#34;https://www.fmjsoft.com/awavestudio.html&#34;&gt;Awave Studio&lt;/a&gt;, a long-running Windows application for converting between sampler formats, reads and writes &lt;a href=&#34;https://www.fmjsoft.com/fmt/fzx.htm&#34;&gt;individual FZ files&lt;/a&gt;: 16-bit mono samples, loop points, names, instruments, and start and end offsets. Envelopes and LFOs are not supported, and neither is the FZ disk format directly. You can move samples in and out at the audio level, but the parts that make an FZ sound like an FZ are still on the other side of the gap.&lt;/p&gt;&#xA;&lt;p&gt;I have been spending time in that gap. &lt;a href=&#34;https://blog.jacobvosmaer.nl/0057-fz-1-images/&#34;&gt;Jacob Vosmaer wrote about the same problem&lt;/a&gt; a few years back, and some of his work was a starting point for mine. The loop is simple: read the spec, write the code, load the disk image onto the Gotek, and check what the bytes look like on the sampler&#39;s front panel. Repeat. It&#39;s a bit tedious. The FZ-10M&#39;s front panel is small to begin with, and one corner of mine is hard to read. Some of it lines up exactly with the 1987 document. Some of it does not. What I&#39;ve been working on should be ready in a few weeks. There will be a short video to go with it.&lt;/p&gt;&#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/article&gt;&#xA;</description>
      <pubDate>Thu, 14 May 2026 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Testing distributed-process Apps Using Hspec</title>
      <link>https://filib.io/posts/2018-12-24-testing-distributed-process-apps-with-hspec.html</link>
      <description>&lt;article class=&#34;post&#34;&gt;&#xA;  &lt;h1&gt;Testing distributed-process Apps Using Hspec&lt;/h1&gt;&#xA;  &lt;header class=&#34;post-meta&#34;&gt;&#xA;    &lt;span class=&#34;post-date&#34;&gt;2018-12-24&lt;/span&gt;&#xA;    &lt;span class=&#34;post-tags&#34;&gt;&lt;a href=&#34;/tags/distributed-process.html&#34; class=&#34;post-category green&#34;&gt;distributed-process&lt;/a&gt; &lt;a href=&#34;/tags/haskell.html&#34; class=&#34;post-category green&#34;&gt;haskell&lt;/a&gt; &lt;a href=&#34;/tags/hspec.html&#34; class=&#34;post-category green&#34;&gt;hspec&lt;/a&gt; &lt;a href=&#34;/tags/testing.html&#34; class=&#34;post-category green&#34;&gt;testing&lt;/a&gt;&lt;/span&gt;&#xA;  &lt;/header&gt;&#xA;  &lt;div class=&#34;post-body&#34;&gt;&#xA;    &lt;p&gt;&lt;a href=&#34;https://github.com/haskell-distributed/distributed-process&#34;&gt;&lt;code&gt;distributed-process&lt;/code&gt;&lt;/a&gt; is a Haskell library that brings Erlang-style concurrency to Haskell. Whilst developing an application at work that uses it, I found that there wasn&#39;t much material online describing how to test &lt;a href=&#34;https://github.com/haskell-distributed/distributed-process&#34;&gt;&lt;code&gt;distributed-process&lt;/code&gt;&lt;/a&gt; applications. I used some techniques from object-oriented programming that allowed me to test the behaviour of my application whilst I was learning how it was supposed to fit together. This post documents some techniques I found useful.&lt;/p&gt;&#xA;&lt;h2 id=&#34;application&#34;&gt;Application&lt;/h2&gt;&#xA;&lt;p&gt;Our example revolves around a fairly simple &lt;a href=&#34;https://en.wikipedia.org/wiki/Client%E2%80%93server_model&#34;&gt;client-server&lt;/a&gt; application. The client process can send data to the server and output responses to the console, whilst the server performs calculations and sends the results back to clients.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;{-# LANGUAGE DeriveGeneric #-}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;{-# LANGUAGE NoImplicitPrelude #-}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;{-# LANGUAGE TupleSections #-}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;module&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Main&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;where&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Control.Distributed.Process&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;ProcessId&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;expect&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;getSelfPid&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;register&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;say&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;send&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;whereis&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Control.Distributed.Process.Node&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;LocalNode&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;initRemoteTable&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;forkProcess&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;newLocalNode&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;runProcess&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Data.Binary&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Binary&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Network.Transport&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Transport&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;..&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Network.Transport.TCP&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;createTransport&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;defaultTCPParameters&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Prelude&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Protolude&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Test.Hspec&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- APP&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;app&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;LocalNode&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;app&lt;/span&gt; node &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; newProcess node &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;client&amp;#34;&lt;/span&gt; clientProcess&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; newProcess node &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt; serverProcess&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  pure &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- PROCESSES&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;ClientMsg&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;Ask&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Result&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;deriving&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Eq&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Generic&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Show&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;instance&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Binary&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;ClientMsg&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;clientProcess&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;clientProcess&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; forever &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  msg &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; expect&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;case&lt;/span&gt; msg &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;of&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Ask&lt;/span&gt; ints &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      self &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; getSelfPid&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      namedSend &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Calc&lt;/span&gt; self ints&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Result&lt;/span&gt; n &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      say &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;received: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; show n&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;ServerMsg&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;Calc&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;ProcessId&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;deriving&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Eq&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Generic&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Show&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;instance&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Binary&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;ServerMsg&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;serverProcess&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;serverProcess&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; forever &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  msg &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; expect&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;case&lt;/span&gt; msg &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;of&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Calc&lt;/span&gt; sender ints &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      send sender &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Result&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;sum ints&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The code above uses some helper functions that aren&#39;t present in &lt;a href=&#34;https://github.com/haskell-distributed/distributed-process&#34;&gt;&lt;code&gt;distributed-process&lt;/code&gt;&lt;/a&gt;; these are included in the code below to let you follow along at home.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- PROCESS HELPERS&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- | Fork process and register it&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;newProcess&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;LocalNode&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;ProcessId&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;newProcess&lt;/span&gt; node name process &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  pid &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; forkProcess node process&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; register name pid&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  pure pid&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- | Create a new transport&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;newTransport&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Either&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;IOException&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Transport&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;newTransport&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    host &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    port &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;3000&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    createTransport host port &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;host&lt;span style=&#34;color:#eceff4&#34;&gt;,)&lt;/span&gt; defaultTCPParameters&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- | Spins up an application&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;run&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;LocalNode&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;LocalNode&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Transport&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;run&lt;/span&gt; app &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  eitherTrans &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; newTransport&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;case&lt;/span&gt; eitherTrans &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;of&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Left&lt;/span&gt; err &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      panic &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; show err&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Right&lt;/span&gt; transport &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      node &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; newLocalNode transport initRemoteTable&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; runProcess node &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;app node&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      pure &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;node&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; transport&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- | Sends to a named process&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;namedSend&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Binary&lt;/span&gt; a&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Typeable&lt;/span&gt; a&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;String&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;namedSend&lt;/span&gt; name msg &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  mbPid &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; whereis name&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;case&lt;/span&gt; mbPid &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;of&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Nothing&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      say &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;process not registered&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Just&lt;/span&gt; pid &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       send pid msg&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;testing&#34;&gt;Testing&lt;/h2&gt;&#xA;&lt;p&gt;We&#39;ll start off by writing a custom &lt;a href=&#34;https://hspec.github.io/writing-specs.html&#34;&gt;HSpec&lt;/a&gt; hook to make a bridge between our application and our tests. Our hook will spin up an application and thread around a shared &lt;a href=&#34;http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Concurrent-MVar.html#t:MVar&#34;&gt;&lt;code&gt;MVar&lt;/code&gt;&lt;/a&gt; and a &lt;a href=&#34;http://hackage.haskell.org/package/distributed-process-0.7.4/docs/Control-Distributed-Process-Node.html#t:LocalNode&#34;&gt;&lt;code&gt;LocalNode&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Concurrent-MVar.html#t:MVar&#34;&gt;&lt;code&gt;MVar&lt;/code&gt;&lt;/a&gt; serves two purposes; it will be used to communicate state and act as locking mechanism (&lt;a href=&#34;http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Concurrent-MVar.html#v:takeMVar&#34;&gt;&lt;code&gt;takeMVar&lt;/code&gt;&lt;/a&gt; blocks until it&#39;s full). Whilst the &lt;a href=&#34;http://hackage.haskell.org/package/distributed-process-0.7.4/docs/Control-Distributed-Process-Node.html#t:LocalNode&#34;&gt;&lt;code&gt;LocalNode&lt;/code&gt;&lt;/a&gt; will allow us to spin up adhoc processes when we need them.&lt;/p&gt;&#xA;&lt;p&gt;The functions &lt;code&gt;aroundApp&lt;/code&gt; and &lt;code&gt;withApp&lt;/code&gt; are the first step in bridging these two worlds.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- SPEC HELPERS&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- | Spins up and tears down app and passing along an mvar&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;aroundApp&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;MVar&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;LocalNode&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;SpecWith&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;MVar&lt;/span&gt; a&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;LocalNode&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Spec&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;aroundApp&lt;/span&gt; app &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  around &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; withApp app&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- | Spins up application, closes it cleanly and passes along an mvar&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;withApp&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;MVar&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;LocalNode&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(((&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;MVar&lt;/span&gt; a&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;LocalNode&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;withApp&lt;/span&gt; app action &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  mvar              &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; newEmptyMVar&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;node&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; transport&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; run &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; app mvar&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  finally &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;action &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;mvar&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; node&lt;span style=&#34;color:#eceff4&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;closeTransport transport&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The second step in bridging these worlds is defining a function that&#39;ll listen for messages that are sent to a process and put them in our &lt;a href=&#34;http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Concurrent-MVar.html#t:MVar&#34;&gt;&lt;code&gt;MVar&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- | Listens for messages and writes msg to an mvar&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;writer&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Binary&lt;/span&gt; a&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Show&lt;/span&gt; a&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Typeable&lt;/span&gt; a&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;MVar&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Process&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;writer&lt;/span&gt; mvar &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  msg &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; expect&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  liftIO &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; putMVar mvar msg&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Using these functions, we&#39;ll write our first test. It&#39;s important that we&#39;re confident our application spins up all of the relevant processes it needs to function correctly. We&#39;ll do this by starting our application, checking whether the process is registered and putting the result in our &lt;a href=&#34;http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Concurrent-MVar.html#t:MVar&#34;&gt;&lt;code&gt;MVar&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- SPECS&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; hspec &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    double mvar node &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; app node&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      x &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; whereis &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;client&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      y &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; whereis &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      liftIO &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; putMVar mvar &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; y&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  aroundApp double &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    describe &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;app&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      it &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;should spin up every process&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;mvar&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        mbPids &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; takeMVar mvar&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        any isNothing mbPids &lt;span style=&#34;color:#eceff4&#34;&gt;`&lt;/span&gt;shouldBe&lt;span style=&#34;color:#eceff4&#34;&gt;`&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;False&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From here we&#39;ll want to test that our processes communicate — i.e. send and receive appropriate messages — with one another as we expect. We do this by starting a client process and registering a server &lt;a href=&#34;https://martinfowler.com/bliki/TestDouble.html&#34;&gt;test double&lt;/a&gt; that&#39;ll listen for messages sent to it using the &lt;code&gt;writer&lt;/code&gt; function.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    double mvar node &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; newProcess node &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;client&amp;#34;&lt;/span&gt; clientProcess&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; newProcess node &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; writer mvar&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      pure &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  aroundApp double &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    describe &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Ask ints&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      it &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;should call the server process&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;mvar&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; node&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; forkProcess node &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          namedSend &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;client&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Ask&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;])&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;Calc&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; ints &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; takeMVar mvar&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ints &lt;span style=&#34;color:#eceff4&#34;&gt;`&lt;/span&gt;shouldBe&lt;span style=&#34;color:#eceff4&#34;&gt;`&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally we&#39;ll want to test our server process calculates results correctly and sends them back to clients. We do this by starting our server process and sending a message to it from a &lt;a href=&#34;https://martinfowler.com/bliki/TestDouble.html&#34;&gt;test double&lt;/a&gt; client process.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    double mvar node &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      void &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; newProcess node &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt; serverProcess&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  aroundApp double &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    describe &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Result i&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      it &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;should call the client process with the result&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;mvar&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; node&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; forkProcess node &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          pid &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; newProcess node &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;client&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; writer mvar&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          namedSend &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Calc&lt;/span&gt; pid &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;Result&lt;/span&gt; i &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; takeMVar mvar&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        i &lt;span style=&#34;color:#eceff4&#34;&gt;`&lt;/span&gt;shouldBe&lt;span style=&#34;color:#eceff4&#34;&gt;`&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;10&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;The approach described in this post reflects some of my background in object-oriented programming. After all, spinning up processes and testing messages passed between them feels very similar to instantiating objects and doing the same thing.&lt;/p&gt;&#xA;&lt;p&gt;There are obviously some shortcomings to the techniques described — the big one being that the type checker doesn&#39;t complain when you send an unknown message to a process. That said, the approach &lt;a href=&#34;https://github.com/haskell-distributed/distributed-process&#34;&gt;&lt;code&gt;distributed-process&lt;/code&gt;&lt;/a&gt; makes you take is very consistent and makes it pleasant to write asynchronous applications.&lt;/p&gt;&#xA;&lt;p&gt;Hopefully what I&#39;ve written here offers some insight into how you might begin testing your &lt;a href=&#34;https://github.com/haskell-distributed/distributed-process&#34;&gt;&lt;code&gt;distributed-process&lt;/code&gt;&lt;/a&gt; applications.&lt;/p&gt;&#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/article&gt;&#xA;</description>
      <pubDate>Mon, 24 Dec 2018 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Parse Ruby Objects in Haskell</title>
      <link>https://filib.io/posts/2017-04-24-parse-ruby-objects-in-haskell.html</link>
      <description>&lt;article class=&#34;post&#34;&gt;&#xA;  &lt;h1&gt;Parse Ruby Objects in Haskell&lt;/h1&gt;&#xA;  &lt;header class=&#34;post-meta&#34;&gt;&#xA;    &lt;span class=&#34;post-date&#34;&gt;2017-04-24&lt;/span&gt;&#xA;    &lt;span class=&#34;post-tags&#34;&gt;&lt;a href=&#34;/tags/haskell.html&#34; class=&#34;post-category green&#34;&gt;haskell&lt;/a&gt; &lt;a href=&#34;/tags/ruby.html&#34; class=&#34;post-category green&#34;&gt;ruby&lt;/a&gt;&lt;/span&gt;&#xA;  &lt;/header&gt;&#xA;  &lt;div class=&#34;post-body&#34;&gt;&#xA;    &lt;p&gt;In 2015 I released my first Haskell project &lt;a href=&#34;https://www.reddit.com/r/haskell/comments/3enysr/my_first_haskell_project_a_ruby_marshal_parser/&#34;&gt;ruby-marshal&lt;/a&gt;. It&#39;s a package that uses the &lt;a href=&#34;https://hackage.haskell.org/package/binary&#34;&gt;binary&lt;/a&gt; package to parse Ruby objects serialised with &lt;a href=&#34;https://ruby-doc.org/core-2.2.2/Marshal.html#method-c-dump&#34;&gt;Marshal.dump&lt;/a&gt;. I wrote it in my spare time because I was curious to know whether I could devise a strategy to incrementally migrate legacy Ruby on Rails applications over to Haskell without the risk associated with a full rewrite.&lt;/p&gt;&#xA;&lt;p&gt;My hypothesis was that if I could decrypt and de-serialise Rails sessions then I&#39;d be able to piggyback on the Rails application&#39;s authentication mechanism. Not long after, I had the opportunity to use this package at work, and put this theory to the test, by writing a Haskell web application that shared sessions with Rails.&lt;/p&gt;&#xA;&lt;p&gt;It has been running in production -- without any issue -- for almost two years.&lt;/p&gt;&#xA;&lt;h2 id=&#34;marshal&#34;&gt;Marshal&lt;/h2&gt;&#xA;&lt;p&gt;Ruby&#39;s &lt;a href=&#34;https://ruby-doc.org/core-2.2.2/Marshal.html&#34;&gt;Marshal&lt;/a&gt; library serialises Ruby objects to a bytestring e.g. dumping &lt;code&gt;true&lt;/code&gt; results in &lt;code&gt;[4, 8, 84]&lt;/code&gt; where &lt;code&gt;4&lt;/code&gt; and &lt;code&gt;8&lt;/code&gt; are the &lt;a href=&#34;https://ruby-doc.org/core-2.2.2/Marshal.html&#34;&gt;Marshal&lt;/a&gt; version number and &lt;code&gt;true&lt;/code&gt; is represented as &lt;code&gt;84&lt;/code&gt; or ASCII &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;% irb&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;irb(main):001:0&amp;gt; &lt;/span&gt; x &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Marshal&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;dump&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\x04\b&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;T&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;irb&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;main&lt;span style=&#34;color:#eceff4&#34;&gt;):&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;002&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;bytes&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;84&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Compound objects, e.g. hash maps, can also be serialised using &lt;a href=&#34;https://ruby-doc.org/core-2.2.2/Marshal.html&#34;&gt;Marshal.dump&lt;/a&gt;. This might explain why it was used as the default cookie serialiser in Rails until version 4.1, after which &lt;a href=&#34;https://github.com/rails/rails/issues/12881&#34;&gt;JSON serialisation became the default&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;% irb&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;irb(main):001:0&amp;gt; &lt;/span&gt; x &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Marshal&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;dump&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;session_id&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;ba0844151d&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\x04\b&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;{&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\x06&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;I&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\&amp;#34;\x0F&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;session_id&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\x06&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\x06&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;ETI&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\&amp;#34;\x0F&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;ba0844151d&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\x06&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;;&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\x00&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;T&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;irb&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;main&lt;span style=&#34;color:#eceff4&#34;&gt;):&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;002&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;bytes&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;123&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;73&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;34&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;115&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;101&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;115&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;115&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;105&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;111&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;110&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;95&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;105&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;58&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;69&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;84&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;73&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;34&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;15&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;98&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;97&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;48&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;56&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;52&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;52&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;49&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;53&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;49&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;6&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;59&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;84&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;More information about the &lt;a href=&#34;https://ruby-doc.org/core-2.2.2/Marshal.html&#34;&gt;Marshal.dump&lt;/a&gt; binary format can be found in a series of blog posts by &lt;a href=&#34;http://jakegoulding.com/blog/2013/01/15/a-little-dip-into-rubys-marshal-format/&#34;&gt;@jakegoulding&lt;/a&gt; or by &lt;a href=&#34;https://github.com/philipcunningham/ruby-marshal/blob/master/src/Data/Ruby/Marshal/Get.hs&#34;&gt;reviewing the ruby-marshal source code&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;design&#34;&gt;Design&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://hackage.haskell.org/package/ruby-marshal&#34;&gt;ruby-marshal&lt;/a&gt; package allows us to transform this binary format into Haskell values and follows a pattern you&#39;ll see elsewhere in the Haskell ecosystem. It consists of:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;An abstract syntax tree (&lt;a href=&#34;https://en.wikipedia.org/wiki/Abstract_syntax_tree&#34;&gt;AST&lt;/a&gt;) that represents Ruby objects.&lt;/li&gt;&#xA;&lt;li&gt;A collection of &lt;a href=&#34;https://en.wikipedia.org/wiki/Parser_combinator&#34;&gt;parser combinators&lt;/a&gt; to transform the &lt;a href=&#34;https://ruby-doc.org/core-2.2.2/Marshal.html&#34;&gt;Marshal&lt;/a&gt; binary representation into an &lt;a href=&#34;https://en.wikipedia.org/wiki/Abstract_syntax_tree&#34;&gt;AST&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;A custom &lt;a href=&#34;https://wiki.haskell.org/Monad&#34;&gt;monad&lt;/a&gt; to enrich the underlying &lt;a href=&#34;https://downloads.haskell.org/~ghc/8.0.1/docs/html/libraries/binary-0.8.3.0/Data-Binary-Get.html#t:Get&#34;&gt;Get monad&lt;/a&gt; with additional effects.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;ast&#34;&gt;AST&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://hackage.haskell.org/package/ruby-marshal-0.1.2/docs/Data-Ruby-Marshal-RubyObject.html#t:RubyObject&#34;&gt;Ruby AST&lt;/a&gt; represents a subset of values that can be encoded by &lt;a href=&#34;https://ruby-doc.org/core-2.2.2/Marshal.html&#34;&gt;Marshal.dump&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RubyObject&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Simple objects.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RNil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RBool&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Bool&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RFixnum&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RFloat&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Float&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RString&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;ByteString&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RSymbol&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;ByteString&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Compound objects.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RArray&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Vector&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RubyObject&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RHash&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Vector&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;RubyObject&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RubyObject&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RIVar&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;RubyObject&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RubyStringEncoding&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Tag for unsupported objects e.g. Bignum.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Unsupported&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a common pattern you&#39;ll see in other packages e.g. &lt;a href=&#34;https://hackage.haskell.org/package/msgpack-1.0.0/docs/Data-MessagePack-Object.html#t:Object&#34;&gt;msgpack:Object&lt;/a&gt; and &lt;a href=&#34;https://hackage.haskell.org/package/aeson-1.2.0.0/docs/Data-Aeson.html#t:Value&#34;&gt;aeson:Value&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;parsers-combinators&#34;&gt;Parsers Combinators&lt;/h3&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Parser_combinator&#34;&gt;Parsers&lt;/a&gt; are combined to build an &lt;a href=&#34;https://en.wikipedia.org/wiki/Abstract_syntax_tree&#34;&gt;AST&lt;/a&gt; e.g. parsing a raw bytestring is defined as follows.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;getString&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Marshal&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;BS&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;ByteString&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;getString&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Label a parser to ensure label will be appended if the parse fails.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  marshalLabel &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;RawString&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Get the number of bytes in the bytestring.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    n &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; getFixnum&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Get the number of bytes in the bytestring and lift it into the Marshal monad.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    liftMarshal &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; getBytes n&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is then used by other parsing functions e.g. parsing a &lt;a href=&#34;https://ruby-doc.org/core-2.2.2/Symbol.html&#34;&gt;Ruby symbol&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;getSymbol&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Marshal&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;BS&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;ByteString&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;getSymbol&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; marshalLabel &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Symbol&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Get bytestring.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  x &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; getString&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Write symbol into the symbol cache.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  writeCache &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RSymbol&lt;/span&gt; x&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Return the bytestring.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  return x&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before being used in the top level parsing function that combines parsing functions and lifts values in to the &lt;a href=&#34;https://hackage.haskell.org/package/ruby-marshal-0.1.2/docs/Data-Ruby-Marshal-RubyObject.html#t:RubyObject&#34;&gt;Ruby AST&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;getRubyObject&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Marshal&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RubyObject&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;getRubyObject&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Make sure we&amp;#39;re using a supported Marshal version, throw away the result and recursively parse our bytestring.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  getMarshalVersion &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; go&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;where&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    go &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Marshal&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RubyObject&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    go &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; liftMarshal getWord8 &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#88c0d0&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;case&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;NilChar&lt;/span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; return &lt;span style=&#34;color:#81a1c1&#34;&gt;RNil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;TrueChar&lt;/span&gt;       &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; return &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RBool&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;True&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;FalseChar&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; return &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RBool&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;False&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;FixnumChar&lt;/span&gt;     &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RFixnum&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getFixnum&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;FloatChar&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RFloat&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getFloat&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;StringChar&lt;/span&gt;     &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RString&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getString&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;SymbolChar&lt;/span&gt;     &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RSymbol&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getSymbol&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;ObjectLinkChar&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RIVar&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getObjectLink&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;SymlinkChar&lt;/span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RSymbol&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getSymlink&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;ArrayChar&lt;/span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RArray&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getArray go&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;HashChar&lt;/span&gt;       &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RHash&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getHash go go&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1&#34;&gt;IVarChar&lt;/span&gt;       &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RIVar&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; getIVar go&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt;              &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; return &lt;span style=&#34;color:#81a1c1&#34;&gt;Unsupported&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;marshal-monad&#34;&gt;Marshal Monad&lt;/h3&gt;&#xA;&lt;p&gt;A quirk of the &lt;a href=&#34;https://ruby-doc.org/core-2.2.2/Marshal.html&#34;&gt;Marshal&lt;/a&gt; format is that it saves space by encoding repeated objects as indexes into a symbol cache and an object cache. We use &lt;code&gt;StateT&lt;/code&gt; to keep track of these during de-serialisation and enrich the underlying &lt;a href=&#34;https://downloads.haskell.org/~ghc/8.0.1/docs/html/libraries/binary-0.8.3.0/Data-Binary-Get.html#t:Get&#34;&gt;Get monad&lt;/a&gt; by creating a custom &lt;a href=&#34;https://wiki.haskell.org/Monad&#34;&gt;monad&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;newtype&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Marshal&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Marshal&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt; runMarshal &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;StateT&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Cache&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Get&lt;/span&gt; a &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;deriving&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Functor&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Applicative&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Monad&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;MonadState&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Cache&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This allows us to write to and read from our cache during parsing without having to manually thread state through our parsing functions.&lt;/p&gt;&#xA;&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;&#xA;&lt;h3 id=&#34;file-io&#34;&gt;File IO&lt;/h3&gt;&#xA;&lt;p&gt;Let&#39;s take a simple example of a Ruby string, serialise it and dump it to the file system using &lt;code&gt;irb&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;% irb&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;irb(main):001:0&amp;gt; &lt;/span&gt; x &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hello haskell&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hello haskell&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;irb&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;main&lt;span style=&#34;color:#eceff4&#34;&gt;):&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;002&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; y &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Marshal&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;dump&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\x04\b&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;I&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\&amp;#34;\x12&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;hello haskell&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\x06&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ebcb8b&#34;&gt;\x06&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;ET&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;irb&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;main&lt;span style=&#34;color:#eceff4&#34;&gt;):&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;003&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;File&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;open&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;example.bin&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt;z&lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; z&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;write&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;y&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Switching over to Haskell we set up our imports.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Data.ByteString&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;ByteString&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Data.Ruby.Marshal&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;qualified&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Data.ByteString&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;as&lt;/span&gt; BS&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;qualified&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Data.ByteString.Char8&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;as&lt;/span&gt; Char8&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Define a function to read our example from the file system.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;readExample&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;ByteString&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;readExample&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;BS&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;readFile &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;example.bin&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Define a function that uses the &lt;a href=&#34;https://hackage.haskell.org/package/ruby-marshal-0.1.2/docs/Data-Ruby-Marshal-RubyObject.html#t:Rubyable&#34;&gt;Rubyable&lt;/a&gt; typeclass to convert a &lt;a href=&#34;https://hackage.haskell.org/package/ruby-marshal-0.1.2/docs/Data-Ruby-Marshal-RubyObject.html#t:RubyObject&#34;&gt;RubyObject&lt;/a&gt; to a more convenient representation.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;toString&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RubyObject&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Maybe&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;ByteString&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;RubyStringEncoding&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;toString&lt;/span&gt; rubyObject &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; fromRuby rubyObject&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before putting it all together to print the Ruby string to the console.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Read example.bin.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  example &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; readExample&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Decode using ruby-marshal and maybe convert the result to a bytestring.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;case&lt;/span&gt; decode example &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; toString &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;of&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Handle the case when serialisation fails.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Nothing&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      putStrLn &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Oops, something went wrong...&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Throw away the encoding information and print the Ruby string to the console.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Just&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;string&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#81a1c1&#34;&gt;Char8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;putStrLn string&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;memcache&#34;&gt;Memcache&lt;/h3&gt;&#xA;&lt;p&gt;Let&#39;s take another example of de-serialising Ruby objects stored in &lt;a href=&#34;https://memcached.org/&#34;&gt;memcache&lt;/a&gt; using the the &lt;a href=&#34;https://github.com/petergoldstein/dalli&#34;&gt;dalli gem&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;% irb&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;irb(main):001:0&amp;gt; &lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;dalli&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;irb&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;main&lt;span style=&#34;color:#eceff4&#34;&gt;):&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;002&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; dc &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Dalli&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;Client&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;new&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;localhost:11211&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;#&amp;lt;Dalli::Client:0x007fe4948b7358 @servers=[&amp;#34;localhost:11211&amp;#34;], @options={}, @ring=nil&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;irb&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;main&lt;span style=&#34;color:#eceff4&#34;&gt;):&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;003&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#b48ead&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&lt;/span&gt; dc&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;set&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;str&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;hello haskell&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&#39;ll reuse our existing Haskell code but add another import.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;qualified&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Database.Memcache.Client&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;as&lt;/span&gt; M&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Define a function that creates a new &lt;a href=&#34;https://memcached.org/&#34;&gt;memcache&lt;/a&gt; client.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;createMemcacheClient&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;Client&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;createMemcacheClient&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;newClient &lt;span style=&#34;color:#eceff4&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;ServerSpec&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b48ead&#34;&gt;11211&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;NoAuth&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;def&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before putting it all together to pull the value out of &lt;a href=&#34;https://memcached.org/&#34;&gt;memcache&lt;/a&gt; and print the Ruby string to the console.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;IO&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;do&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Set up memcache client.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  mc &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; createMemcacheClient&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Retrieve bytestring from memcache server.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  example &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;M&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;get mc &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;str&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Unpack result from memcache server.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;case&lt;/span&gt; example &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;of&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Nothing&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      putStrLn &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Oops, key not found...&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Pattern match to extract bytestring.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;Just&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;value&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Decode using ruby-marshal and maybe convert the result to a bytestring.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;case&lt;/span&gt; decode value &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; toString &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;of&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Handle the case when serialisation fails.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;Nothing&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          putStrLn &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;Oops, something went wrong...&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;-- Throw away the encoding information and print the Ruby string to the console.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#81a1c1&#34;&gt;Just&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;string&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#81a1c1&#34;&gt;Char8&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;putStrLn string&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;By writing the &lt;a href=&#34;https://hackage.haskell.org/package/ruby-marshal&#34;&gt;ruby-marshal&lt;/a&gt; package, I was able to create a Haskell web application that coexisted with a Rails application. This approach has been a success at work and appears to be one way in which you could gradually migrate an existing web application written in Ruby over to Haskell without the risk associated with a full rewrite.&lt;/p&gt;&#xA;&lt;h2 id=&#34;links&#34;&gt;Links&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/philipcunningham/ruby-marshal&#34;&gt;https://github.com/philipcunningham/ruby-marshal&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://hackage.haskell.org/package/ruby-marshal&#34;&gt;https://hackage.haskell.org/package/ruby-marshal&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://hackage.haskell.org/package/rails-session&#34;&gt;https://hackage.haskell.org/package/rails-session&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/article&gt;&#xA;</description>
      <pubDate>Mon, 24 Apr 2017 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Writing PureScript Bindings for a jQuery Plugin</title>
      <link>https://filib.io/posts/2015-11-06-writing-purescript-bindings-for-a-jquery-plugin.html</link>
      <description>&lt;article class=&#34;post&#34;&gt;&#xA;  &lt;h1&gt;Writing PureScript Bindings for a jQuery Plugin&lt;/h1&gt;&#xA;  &lt;header class=&#34;post-meta&#34;&gt;&#xA;    &lt;span class=&#34;post-date&#34;&gt;2015-11-06&lt;/span&gt;&#xA;    &lt;span class=&#34;post-tags&#34;&gt;&lt;a href=&#34;/tags/javascript.html&#34; class=&#34;post-category green&#34;&gt;javascript&lt;/a&gt; &lt;a href=&#34;/tags/purescript.html&#34; class=&#34;post-category green&#34;&gt;purescript&lt;/a&gt;&lt;/span&gt;&#xA;  &lt;/header&gt;&#xA;  &lt;div class=&#34;post-body&#34;&gt;&#xA;    &lt;p&gt;You&#39;ve started a new project at work with a tight deadline. You&#39;re in charge of&#xA;picking the stack and after assessing technologies best for the project you&#39;ve&#xA;decided to use &lt;a href=&#34;http://www.purescript.org/&#34;&gt;PureScript&lt;/a&gt; on the front-end. One&#xA;factor determining the success of the project is that it be delivered on time.&lt;/p&gt;&#xA;&lt;p&gt;PureScript is the technology I chose for a new project at work and one of the&#xA;ways it&#39;s helping my company deliver our project on time is by allowing us to&#xA;leverage existing JavaScript libraries using its&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Foreign_function_interface&#34;&gt;foreign function interface (FFI)&lt;/a&gt;,&#xA;whilst still allowing us to exploit strong typing. The experience of writing FFI&#xA;bindings has been so positive that I wanted to share with you how you might&#xA;write your own bindings for an existing&#xA;&lt;a href=&#34;https://github.com/jquery/jquery&#34;&gt;jQuery&lt;/a&gt; plugin.&lt;/p&gt;&#xA;&lt;p&gt;In this post, together we&#39;ll be writing bindings for a subset of the&#xA;functionality of &lt;a href=&#34;https://github.com/rstaib/jquery-steps&#34;&gt;jQuery-steps&lt;/a&gt;: a&#xA;lightweight wizard UI component written for jQuery. This won&#39;t be a deep dive&#xA;into PureScript&#39;s FFI but will give you an insight into some of the practical&#xA;considerations involved in using JavaScript code from PureScript. It assumes&#xA;familiarity with JavaScript, PureScript and jQuery.&lt;/p&gt;&#xA;&lt;h2 id=&#34;ffi&#34;&gt;FFI&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://leanpub.com/purescript/read#leanpub-auto-the-foreign-function-interface&#34;&gt;PureScript&#39;s FFI&lt;/a&gt;&#xA;allows communication from PureScript code to JavaScript code. It&#39;s&#xA;straight-forward and flexible, making it possible to write bindings for even the&#xA;most involved JavaScript code. Provided, that is, that you understand the&#xA;underlying runtime representation of what you&#39;re dealing with.&lt;/p&gt;&#xA;&lt;h2 id=&#34;configuration&#34;&gt;Configuration&lt;/h2&gt;&#xA;&lt;p&gt;As is typical for jQuery plugins, jQuery-steps takes a configuration object to&#xA;tell it which DOM elements it should bind to. We begin by defining the types&#xA;we&#39;ll need to safely represent the fields of this configuration object in&#xA;PureScript.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;module&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;JQuery.Steps&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;where&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Control.Monad.Eff&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Control.Monad.Eff.JQuery&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Control.Monad.Eff.Unsafe&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;DOM&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Data.Foreign.Callback&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Data.Function&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Prelude&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;newtype&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;HeaderTag&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;HeaderTag&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;String&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;newtype&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;BodyTag&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;BodyTag&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;String&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;newtype&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;CssClass&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;CssClass&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;String&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We use &lt;a href=&#34;https://leanpub.com/purescript/read#leanpub-auto-newtypes&#34;&gt;newtype&lt;/a&gt;&#xA;wrappers to represent the values of the fields in our configuration object. We&#xA;do this because newtypes have the same runtime representation as the underlying&#xA;type, whilst being distinct from the perspective of the type checker. This makes&#xA;newtypes an easy win for providing an extra layer of type safety when defining&#xA;FFI bindings.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Config&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt; headerTag &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;HeaderTag&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; bodyTag   &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;BodyTag&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; cssClass  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;CssClass&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We use a&#xA;&lt;a href=&#34;https://leanpub.com/purescript/read#leanpub-auto-defining-our-types&#34;&gt;type synonym&lt;/a&gt;&#xA;to represent our configuration rather than an&#xA;&lt;a href=&#34;https://leanpub.com/purescript/read#leanpub-auto-algebraic-data-types&#34;&gt;algebraic data type&lt;/a&gt;&#xA;(ADT). Much like a newtype, the type synonym&#39;s runtime representation will have&#xA;a direct correspondence with what jQuery-steps expects, whereas an ADT&#39;s&#xA;constructors would present an extra level of indirection that we&#39;d have to&#xA;handle in our JavaScript wrapper.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;defaultConfig&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Config&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;defaultConfig&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt; headerTag&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;HeaderTag&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;h1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; bodyTag&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;BodyTag&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;div&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; cssClass&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;CssClass&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;wizard&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We define a default configuration object to let consumers of our bindings use&#xA;&lt;a href=&#34;https://leanpub.com/purescript/read#leanpub-auto-putting-row-polymorphism-to-work&#34;&gt;record update syntax&lt;/a&gt;&#xA;to override the defaults we&#39;ve set.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;var&lt;/span&gt; defaultConfig &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      headerTag&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;h1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; bodyTag&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;div&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; cssClass&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;wizard&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here&#39;s what &lt;strong&gt;defaultConfig&lt;/strong&gt; will look like at runtime. You can see that&#xA;despite adding an extra layer of type safety when working with our configuration&#xA;object in PureScript, we don&#39;t pay any extra cost for the abstraction at&#xA;runtime. Practically speaking, this means that we can pass our configuration&#xA;object directly to jQuery-steps.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;/*global exports, jQuery*/&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;use strict&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;// module JQuery.Steps&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exports&lt;span style=&#34;color:#eceff4&#34;&gt;.&lt;/span&gt;steps &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;object&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;return&lt;/span&gt; jQuery&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;object&lt;span style=&#34;color:#eceff4&#34;&gt;).&lt;/span&gt;steps&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#eceff4&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;};&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We define our export function that wraps jQuery-steps by providing a&#xA;&lt;a href=&#34;https://leanpub.com/purescript/read#leanpub-auto-curried-functions&#34;&gt;curried&lt;/a&gt;&#xA;interface. It&#39;s worth noting that we&#39;re using the FFI style introduced in&#xA;&lt;a href=&#34;https://github.com/purescript/purescript/wiki/0.7-Migration-Guide#no-more-inline-ffi-code&#34;&gt;PureScript 0.7&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;foreign&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;steps&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; forall eff&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;JQuery&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Config&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Eff&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;dom &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;DOM&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;|&lt;/span&gt; eff&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Unit&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And, finally, we write a foreign import declaration and we&#39;re done. It&#39;s really&#xA;as simple as that. Well, almost.&lt;/p&gt;&#xA;&lt;h2 id=&#34;callbacks-and-dishonesty&#34;&gt;Callbacks and Dishonesty&lt;/h2&gt;&#xA;&lt;p&gt;Binding to DOM elements is all well and good but very soon you&#39;ll want to add&#xA;dynamic behaviour such as client-side validation. This means delving into into&#xA;the unprincipled world of JavaScript callbacks and exposing the plugin&#39;s event&#xA;handler API.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Config&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt; headerTag   &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;HeaderTag&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; bodyTag     &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;BodyTag&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; cssClass    &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;CssClass&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; onFinished  &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Callback2&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;JQueryEvent&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Unit&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; onFinishing &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Fn3&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;JQueryEvent&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Boolean&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We begin by extending &lt;strong&gt;Config&lt;/strong&gt; to include two new fields: &lt;strong&gt;onFinished&lt;/strong&gt; and&#xA;&lt;strong&gt;onFinishing&lt;/strong&gt;. The type constructor &lt;strong&gt;Callback2&lt;/strong&gt; comes from&#xA;&lt;a href=&#34;https://github.com/fluffynukeit/purescript-foreign-callbacks&#34;&gt;purescript-foreign-callbacks&lt;/a&gt;&#xA;and represents an effectful computation that takes two arguments, whilst the&#xA;type constructor &lt;strong&gt;Fn3&lt;/strong&gt; comes from&#xA;&lt;a href=&#34;https://github.com/purescript/purescript-functions&#34;&gt;purescript-functions&lt;/a&gt; and&#xA;represents a pure function that takes three arguments.&lt;/p&gt;&#xA;&lt;p&gt;Something seems a bit odd here - why is &lt;strong&gt;onFinished&lt;/strong&gt; effectful, whilst&#xA;&lt;strong&gt;onFinishing&lt;/strong&gt; is pure? Well, the truth is that they are both effectful, but&#xA;since JavaScript offers no means of distinguishing between effectful and pure&#xA;computations, we need to circumvent the type checker to ensure functions we pass&#xA;to &lt;strong&gt;onFinishing&lt;/strong&gt; have the correct runtime representation.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;mkFinishing&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; forall a&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;JQueryEvent&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Eff&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1&#34;&gt;Boolean&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Fn3&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;JQueryEvent&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Boolean&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;mkFinishing&lt;/span&gt; f &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; mkFn3 &lt;span style=&#34;color:#88c0d0&#34;&gt;\&lt;/span&gt;x y z &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; runPure &lt;span style=&#34;color:#81a1c1&#34;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; unsafeInterleaveEff &lt;span style=&#34;color:#81a1c1&#34;&gt;$&lt;/span&gt; f x y z&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;mkFinishing&lt;/strong&gt; transforms our function into an appropriate runtime&#xA;representation by uncurrying it and by unsafely pulling the inner value out of&#xA;the &lt;strong&gt;Eff&lt;/strong&gt; constructor. We uncurry our function because JavaScript functions&#xA;aren&#39;t curried by default and we pull the inner value out of &lt;strong&gt;Eff&lt;/strong&gt; because&#xA;jQuery-steps expects a callback that returns a boolean value.&lt;/p&gt;&#xA;&lt;p&gt;If at this point you&#39;re feeling a little uncomfortable, that&#39;s OK. Once a value&#xA;is inside &lt;strong&gt;Eff&lt;/strong&gt; you shouldn&#39;t really be pulling it back out without a very&#xA;good reason. But we&#39;re dealing with JavaScript code here and managing the&#xA;impedance mismatch, so consumers of our bindings don&#39;t have to, is probably&#xA;reason enough. In any case, the callback function wouldn&#39;t be very useful if it&#xA;was pure!&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;mkFinished&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; forall a&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;JQueryEvent&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Eff&lt;/span&gt; a &lt;span style=&#34;color:#81a1c1&#34;&gt;Unit&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Callback2&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;JQueryEvent&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Int&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Unit&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;mkFinished&lt;/span&gt; f &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; callback2 f&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;mkFinished&lt;/strong&gt;, on the other hand, is much simpler. It uses&#xA;&lt;a href=&#34;https://github.com/fluffynukeit/purescript-foreign-callbacks/blob/5c6502fcb0b53e51b69c76e437cfa3e9e177ddf5/src/Data/Foreign/Callback.js#L15-L17&#34;&gt;callback2&lt;/a&gt;&#xA;to take our effectful computation of two arguments and transforms it into an&#xA;appropriate runtime representation for jQuery-steps.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;defaultConfig&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;::&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;Config&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#88c0d0&#34;&gt;defaultConfig&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;{&lt;/span&gt; headerTag&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;HeaderTag&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;h1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; bodyTag&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;BodyTag&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;div&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; cssClass&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#81a1c1&#34;&gt;CssClass&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;wizard&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; onFinished&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; mkFinished &lt;span style=&#34;color:#88c0d0&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; return unit&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; onFinishing&lt;span style=&#34;color:#81a1c1&#34;&gt;:&lt;/span&gt; mkFinishing &lt;span style=&#34;color:#88c0d0&#34;&gt;\&lt;/span&gt;&lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#81a1c1;font-weight:bold&#34;&gt;-&amp;gt;&lt;/span&gt; return true&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#eceff4&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And, finally, here&#39;s what the resulting &lt;strong&gt;defaultConfig&lt;/strong&gt; looks like. Now we&#39;re&#xA;really done. That wasn&#39;t so bad, was it?&lt;/p&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;PureScript lets us easily reuse existing JavaScript libraries with help from its&#xA;FFI. Being able to reuse code can help us prototype more rapidly by allowing us&#xA;to stand on the shoulders of giants. Combining this property with a strongly&#xA;typed language can help us when that rapid prototype needs to make its way into&#xA;a production setting.&lt;/p&gt;&#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/article&gt;&#xA;</description>
      <pubDate>Fri, 06 Nov 2015 00:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Using Loggly On Elastic Beanstalk</title>
      <link>https://filib.io/posts/2015-07-19-using-loggly-on-elastic-beanstalk.html</link>
      <description>&lt;article class=&#34;post&#34;&gt;&#xA;  &lt;h1&gt;Using Loggly On Elastic Beanstalk&lt;/h1&gt;&#xA;  &lt;header class=&#34;post-meta&#34;&gt;&#xA;    &lt;span class=&#34;post-date&#34;&gt;2015-07-19&lt;/span&gt;&#xA;    &lt;span class=&#34;post-tags&#34;&gt;&lt;a href=&#34;/tags/ops.html&#34; class=&#34;post-category green&#34;&gt;ops&lt;/a&gt;&lt;/span&gt;&#xA;  &lt;/header&gt;&#xA;  &lt;div class=&#34;post-body&#34;&gt;&#xA;    &lt;p&gt;This week I had to configure a Rails app running on Elastic Beanstalk&#xA;to use Loggly. Since I don&#39;t want anyone to suffer the Elastic&#xA;Beanstalk documentation more than is necessary, I&#39;ve written this&#xA;short tutorial should you find yourself tasked with the same&#xA;challenge. It assumes you already have a Rails app running on Elastic&#xA;Beanstalk and a general understanding of Rails apps.&lt;/p&gt;&#xA;&lt;h2 id=&#34;configure-app&#34;&gt;Configure App&lt;/h2&gt;&#xA;&lt;p&gt;Add the &lt;a href=&#34;https://github.com/crohr/syslogger&#34;&gt;syslogger&lt;/a&gt; gem to your Gemfile.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# Gemfile&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gem &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;syslogger&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#39;~&amp;gt; 1.6.0&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In &lt;code&gt;config/environments/production.rb&lt;/code&gt; configure your app to use&#xA;&lt;code&gt;Syslogger&lt;/code&gt; for logging. Replace &lt;code&gt;&amp;quot;your-app-name&amp;quot;&lt;/code&gt; with, you guessed&#xA;it, the name of your application. This allows you to easily see logs&#xA;from your app in the Loggly web interface using&#xA;&lt;a href=&#34;https://www.loggly.com/docs/source-groups/&#34;&gt;source groups&lt;/a&gt;, which is&#xA;especially useful if you&#39;re using Loggly to aggregate logs from&#xA;multiple apps.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# config/environments/production.rb&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;config&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;logger &lt;span style=&#34;color:#81a1c1&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Syslogger&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;.&lt;/span&gt;new&lt;span style=&#34;color:#eceff4&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;your-app-name&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Syslog&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;LOG_PID&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#8fbcbb&#34;&gt;Syslog&lt;/span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#8fbcbb&#34;&gt;LOG_LOCAL7&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;create-loggly-account&#34;&gt;Create Loggly Account&lt;/h2&gt;&#xA;&lt;p&gt;Go &lt;a href=&#34;https://www.loggly.com/signup/&#34;&gt;sign up&lt;/a&gt; for a&#xA;&lt;a href=&#34;https://www.loggly.com/&#34;&gt;Loggly&lt;/a&gt; account and&#xA;&lt;a href=&#34;https://www.loggly.com/docs/customer-token-authentication-token/&#34;&gt;create a customer token&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;configure-container-environment&#34;&gt;Configure Container Environment&lt;/h2&gt;&#xA;&lt;p&gt;Go to the Amazon AWS Console and add your Loggly account name and&#xA;customer token to your Elastic Beanstalk app&#39;s environment using the&#xA;&lt;code&gt;LOGGLY_ACCOUNT&lt;/code&gt; and &lt;code&gt;LOGGLY_AUTH&lt;/code&gt; property names.&lt;/p&gt;&#xA;&lt;h2 id=&#34;customise-container&#34;&gt;Customise Container&lt;/h2&gt;&#xA;&lt;p&gt;Add the following configuration to &lt;code&gt;loggly.config&lt;/code&gt; in the &lt;code&gt;.ebextensions&lt;/code&gt;&#xA;directory in the root of your app.&lt;/p&gt;&#xA;&lt;pre style=&#34;color:#d8dee9;background-color:#2e3440;-webkit-text-size-adjust:none;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87;font-style:italic&#34;&gt;# .ebextensions/loggly.config&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;files&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;/tmp/loggly_config.sh&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;mode&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a3be8c&#34;&gt;&amp;#34;000755&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;owner&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; root&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;group&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; root&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;content&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#eceff4&#34;&gt;|&lt;/span&gt;&lt;span style=&#34;color:#616e87&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87&#34;&gt;      #!/bin/bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#616e87&#34;&gt;      su --command=&amp;#34;python /tmp/configure-syslog.py setup --auth $LOGGLY_AUTH --account $LOGGLY_ACCOUNT --yes&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#81a1c1&#34;&gt;container_commands&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;01_loggly_dl&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      wget -q -O /tmp/configure-syslog.py https://www.loggly.com/install/configure-syslog.py&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#81a1c1&#34;&gt;02_loggly_config&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#81a1c1&#34;&gt;command&lt;/span&gt;&lt;span style=&#34;color:#eceff4&#34;&gt;:&lt;/span&gt; /tmp/loggly_config.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This YAML file downloads Loggly&#39;s own syslog configuration script and&#xA;sets up your container to send your system logs to Loggly. You can&#xA;audit this script at&#xA;&lt;a href=&#34;https://github.com/loggly/install-script/blob/master/configure-syslog.py&#34;&gt;loggly/install-script&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap Up&lt;/h2&gt;&#xA;&lt;p&gt;Re-deploy your app to Elastic Beanstalk and watch as your logs begin&#xA;appearing in Loggly.&lt;/p&gt;&#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/article&gt;&#xA;</description>
      <pubDate>Sun, 19 Jul 2015 00:00:00 +0000</pubDate>
    </item>
  </channel>
</rss>