<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Lettier on Medium]]></title>
        <description><![CDATA[Stories by Lettier on Medium]]></description>
        <link>https://medium.com/@lettier?source=rss-dd4eda19e229------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*DM2bfIVj3LLgyG3hMirauw.png</url>
            <title>Stories by Lettier on Medium</title>
            <link>https://medium.com/@lettier?source=rss-dd4eda19e229------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 05:03:08 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@lettier/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[How To Create Hand Painted Textures Without Painting]]></title>
            <link>https://medium.com/@lettier/how-to-create-hand-painted-textures-without-painting-aa7374fef815?source=rss-dd4eda19e229------2</link>
            <guid isPermaLink="false">https://medium.com/p/aa7374fef815</guid>
            <category><![CDATA[design]]></category>
            <category><![CDATA[indiedev]]></category>
            <category><![CDATA[graphic-design]]></category>
            <category><![CDATA[game-development]]></category>
            <category><![CDATA[gamedev]]></category>
            <dc:creator><![CDATA[Lettier]]></dc:creator>
            <pubDate>Sun, 13 Jan 2019 22:47:22 GMT</pubDate>
            <atom:updated>2021-07-06T04:18:33.866Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xyuIj-NPEoW_-L2a-iseuw.png" /></figure><p>The hand-painted look is a compelling game art style. It adds a whimsically fantastical feel that photorealism lacks. However, actually achieving the look can be quite tedious — sometimes requiring hours for a single texture.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*pO-0ODTVWFsdS7jSPZLknw.gif" /><figcaption>Everyone’s favorite hand-painted texture — the brick wall.</figcaption></figure><p>Below is a way I’ve come up with for approximating the hand-painted look that can stand on its own — or if needed — be the basis for a hand-painted texture without having to start from a blank canvas. This process is especially helpful for those pressed for time, say during a game jam.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hYwUci_aPLOTuN2Vw9i3Iw.png" /></figure><p>The nice thing about this technique is that you can dial in how much or how little stylization you want.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*loGtVYSrGgYUIn46rQ77rA.gif" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CC2LN_GK00IuWY6litTJDw.gif" /></figure><p>Using it on a variety of textures, I haven’t found a case where it completely fails to give that hand painted look.</p><h4>Finding A Photo Texture</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VibuD9bU0cMgLwzqIjyB2Q.jpeg" /><figcaption><a href="https://pixabay.com/photos/old-pavement-footpath-moss-stone-19777/">Link</a> to the original.</figcaption></figure><p>The process starts with a real photo. Somewhere in the photo you choose is a hand-painted texture lurking in the details. Your goal is to remove the right details to reveal the hand-painted texture hidden underneath. When you’re actually painting the texture, you’re trying to build up the details while here, you are trying to tear them down.</p><p>I tend to use <a href="https://pixabay.com/">Pixabay</a> to find my photo textures. Most of the images are free for commercial use and require no attribution which is always nice when developing your own game.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jxXXGj_B0DXTXszLJb-1dA.png" /></figure><p>⚠️ Make sure to find one evenly lit and head on when browsing through the photos.</p><h4>Preparing The Photo</h4><p>Depending on your needs, you might be able to skip the photo prep. However, in the interest of documenting the most involved case, I’ll demonstrate the technique by creating a seamless/tileable, square, power-of-two texture which tends to be the most versatile.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Y4ibdcwDwqawIOkTBAmSpw.png" /><figcaption>Click the image to enlarge it.</figcaption></figure><p>The photo I’ve chosen is a bit bowed so you’ll want to straighten it out before you do anything. You can do this with the warp tool.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zu1LOBP9x21iiIhreJ_nAg.png" /></figure><p>Next, crop the photo where the width and height are the same size and a power of two (256x256, 512x512, 1024x1024, etc.). To help make the texture seamless, try to crop it in such a way that the left and right and the top and bottom sort of mirror each other.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2GTgP4m61GoKXQsfSRu-Kg.png" /></figure><p>If you don’t already have it, make sure to install <a href="https://gmic.eu/">G’MIC</a>. I use it as a <a href="https://krita.org/">Krita</a> plugin but you can also use it <a href="https://gmicol.greyc.fr/">online</a>. With G’MIC open, find the Make Seamless [Diffusion] filter. This will help remove the seams without having to use the heal/patch or clone tool.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cCxXEW3Vzi1QPDKjGf4iUA.png" /></figure><p>The seams should be more or less gone now. However, the Make Seamless filter tends to introduce uneven lighting so you’ll have to play around with the Equalize Light setting. If the Equalize Light setting doesn’t work, you can try the Normalize Brightness filter after using Make Seamless.</p><h4>Splitting The Details</h4><p>With the prep done, we can now move on to the stylization.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*36tnnd3j9o5s1OlGPD5LFA.png" /></figure><p>With G’MIC open, go to the Split Details [Wavelets] filter. Set the Number of Scales to four and click apply. The first split is the small details, the second is the medium details, the third is the large details, and the fourth is the residual or what’s left over. You can try more or less splits but I’ve found four to be the ideal number.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZR5VLn_GsR3DIA_aREScEw.png" /></figure><p>After splitting the details, rename the layers 1 through 4 so you can easily reference them later. Layer 1, 2, and 3 should be set to Grain Merge. After setting the blend mode, you’ll notice that you have the original image back.</p><h4>Adding The Brush Strokes</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*m1gBjq4oZcQRvSecF9CzOg.png" /></figure><p>It wouldn’t be hand painted without brush strokes. After splitting the details, run layer 4 through the Brushify filter found in G’MIC.</p><p>Under the Brush Parameters, set the Shape to Rectangle, the Number of Sizes to 2, the Maximal Size to 45, the Light Type to None, the Light Strength to 0, and the Opacity to 1. These are the ideals settings I’ve found but feel free to experiment. Depending on how “painted” you want it to look, play around with the Number of Sizes.</p><p>💡 The goal here is to see the brush strokes so having it rough around the edges is fine. You want it to look like the colors and shading have all been roughed in but haven’t been smoothed out yet.</p><h4>Smoothing Out The Details</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pB40Kv0LLLNBvTT-jyaCJQ.png" /></figure><p>Recall that our goal is to remove just enough detail to reveal the hidden hand painted texture underneath. Layers 1 through 3 hold the small, medium, and large details respectively. For layers 1, 2, and 3, you’ll want to smooth out the details until they each have that chunky, painterly look.</p><p>With G’MIC open, navigate to the Smooth [Thin Brush] filter. I’ve found this smoothing filter to work the best for this step but feel free to try the others. The goal here is to retain the important edges or contours while blurring out the rest.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xwheoIRttXroWPNI5L0Tcg.gif" /></figure><p>Here you see me smoothing out layer 1. I take out most of the detail, retaining just a slight hint of the surface detail found on the stones and moss.</p><h4>Seamless</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AsGR60jOtMyetEV06TI4lQ.gif" /></figure><p>After using Brushify on layer 4 and Smooth [Thin Brush] on layers 1 through 3, we have seams again. To remedy this, apply the Make Seamless filter to layers 3 and 4. You can try it on layers 2 and 1 but I’ve found it does more harm than good.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BZ6KW-iHrVaB4-gAaIbNig.png" /></figure><p>For example, here you see Make Seamless applied to layer 2. Notice the uneven lighting where it looks pinched in certain spots.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*H65iskMGVLeGHJWdGY0NUw.gif" /></figure><p>To remove the seams in layers 1 and 2, use the clone tool to lightly smooth away the obvious edges.</p><p>⚠️ Be careful not to introduce phantom details by cloning some detail that wasn’t there before.</p><h4>Creating The Normal Map</h4><p>So far we’ve been working on the diffuse map. The diffuse map defines the color of your game model as if it was fully lit. However, we’d like to incorporate the surface details we see in the diffuse map into the shading or lighting performed by the game engine. To do that, we’ll need to create a normal map.</p><p>💡 To learn more about the technical side of normal mapping, be sure to check out <a href="https://github.com/lettier/3d-game-shaders-for-beginners">3D Game Shaders For Beginners</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jIe8bEgQQz9_2m5_dGMSKQ.png" /></figure><p>Before creating the normal map, take a look at layers 1 through 3 and decide on how much detail you would like to incorporate. Typically, layer 3 is enough but sometimes I add in layer 2 as well.</p><p>After you have decided how much detail to include, copy the layers and merge them together. Move this layer up above 1 and set its blend mode to normal. Now take this layer and desaturate it using the average setting.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*me-mIlpYiF2FfZsh8bL00A.png" /></figure><p>At this point, you’ll want to look up how to create a normal map using your preferred program. For Krita, it has a built-in filter called Height to Normal Map. Select Filter ▶️ Edge Detection ▶️ Height to Normal Map and choose from either Prewitt, Sobel, or Simple. I tend to use Sobel or Simple the most. If the details are extra light then I’ll choose Prewitt. After clicking OK, rename this layer normal and hide every layer.</p><h4>Creating The Cavity Map</h4><p>From the normal map we’ll create the cavity map. The cavity map allows us to highlight the sharp ridges and shadow the narrow crevices found in the texture.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oNZ9cK5D7JsPcemh7qFbQA.png" /></figure><p>Select the normal map and then navigate to Image ▶️ Separate Image. This will separate the normal map into its blue, red, and green channels.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*37K67bUOCKCXsNonvrn0Pg.png" /></figure><p>Select the blue layer and set it to multiply. Select the green layer and set it to overlay. With the green layer still selected, navigate to Filter ▶️ Edge Detection ▶️ Edge Detection. Like the normal map, select from either Prewitt, Sobel, or Simple. For the green layer, set the Output to Bottom Edge and click OK. Now do the same for the red layer but this time set the Output to Right Edge.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tlXkz5VcZYHUk5fUCffXIQ.png" /></figure><p>After the edge detection, merge the green layer into the red layer and then merge the blue layer into the red layer. Rename this layer cavity and place it above layer 1. Set the blend mode for cavity to overlay.</p><p>The cavity map most likely has seams so you’ll want to try using Make Seamless and if that doesn’t work, clean up the edges using the clone tool like you did before.</p><p>At this point the cavity map is finished but you may want to adjust its contrast in case the highlights are too harsh and/or smooth it out with the Thin Brush filter if it’s too noisy.</p><h4>Creating The Occlusion Map</h4><p>The last map we’ll create is the ambient occlusion map. This map allows us to shadow the larger recessed regions in our texture that receive less light. Your game engine can also use it when it applies the ambient lighting.</p><p>The cavity map and ambient occlusion map tend to overlap but in general the ambient occlusion map shadows the larger occluded areas while the cavity map handles the smaller occluded areas. The cavity map also highlights the sharply raised areas.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rd1HVGEVTcUM-aNIeekrjw.png" /></figure><p>Similar to the normal map, select, copy, and merge the details layers you would like to include in the ambient occlusion map. Once merge, desaturate this new layer using the Min option.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ULPTCFak6pgpyKUwihfV9g.png" /></figure><p>With G’MIC open, navigate to the Basic Adjustments filter. Play with the brightness and contrast until you have the desired result. You&#39;ll want the raised areas to be white and the recessed areas to be a soft grey. When you have the look you want, press Apply and set this layer’s blend mode to multiply.</p><h4>Color Correction</h4><p>The stylization process is now complete but before you export you may want to perform some color correction on layer 4.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s8WmG_ya4qnYb9QY7_1Zmw.png" /></figure><p>I enjoy using the G’MIC Basic Adjustments filter for this step.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*C8WzYOu8H_6nL5E3kvUoCw.png" /></figure><p>Another filter to try is G’MIC’s Auto Balance. This may not always work but when it does, it can definitely save some time when you’re trying to get the colors just right.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IJ31yG8pGE4PMkFxQNcHaw.gif" /></figure><p>Just before I export, I like to toggle on and off the original. This allows me to see how much of a change I made, whether or not I got all the details I wanted, and if I overdid it with the color correction.</p><h4>Putting It All Together</h4><p>You now have your diffuse, normal, ambient occlusion, and cavity map.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s5I3k0a4C3DD5iayRGMDdA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*gqCjVEUWHfFuPjd5NiJXkQ.gif" /><figcaption>GIF created with <a href="https://github.com/lettier/gifcurry">Gifcurry</a>.</figcaption></figure><p>With these maps, you can now move over to your modeling program (I use <a href="https://www.blender.org/">Blender</a>) and assemble your material.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*s4zzSiqjp35fF358CZVoww.gif" /><figcaption>GIF created with <a href="https://github.com/lettier/gifcurry">Gifcurry</a>.</figcaption></figure><p>In this scene, I used the same process described up above to create the wood, roof, grass, water, rope, bark, butterfly, rock, leaves, shrub, and metal texture. I’ve <a href="https://sketchfab.com/3d-models/the-well-fde6871866294d9fa9b46119e1358715">uploaded the model to Sketchfab</a> so you can take a closer look.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fJV5LCjOLFaN8Po6zTasXA.png" /></figure><p>Using only a couple of free tools (Krita and G’MIC), I’ve put together a fairly easy process for creating diffuse, normal, cavity, and occlusion maps that approximate the hand-painted game art style.</p><p>Hopefully this will save you some time when developing your own games. If you happen to use the process, be sure to share your creation in the comments below. 👍</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aa7374fef815" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Create 3D Games with PureScript Native and C++]]></title>
            <link>https://medium.com/@lettier/how-to-create-3d-games-with-purescript-and-cpp-faabf8f27fe6?source=rss-dd4eda19e229------2</link>
            <guid isPermaLink="false">https://medium.com/p/faabf8f27fe6</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[haskell]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[purescript]]></category>
            <category><![CDATA[game-development]]></category>
            <dc:creator><![CDATA[Lettier]]></dc:creator>
            <pubDate>Tue, 18 Dec 2018 03:04:55 GMT</pubDate>
            <atom:updated>2019-09-08T05:16:48.419Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/630/1*okLMRpRzgBaLdU_XvE2kOQ.gif" /></figure><p>When I <a href="https://lettier.github.io/posts/2017-10-23-animation-purescript-cpp-sfml.html">last wrote about binding PureScript to C++</a>, I demonstrated animating the PureScript logo with SFML. Since then, <a href="https://github.com/andyarvanitis/purescript-native">PureScript Native</a> (PSN) has superseded Pure11 and the details for using PSN have changed.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*zDSPG4PGiLUFGuzzEJok4Q.gif" /></figure><p>To make this concrete, I’ll go over what it took to create <a href="https://github.com/lettier/lambda-lantern">Lambda Lantern</a> — a 3D game about functional programming patterns. Originally Lambda Lantern started off as a <a href="https://itch.io/jam/game-off-2018/rate/338096">GitHub Game Off submission</a>. Since you only have 30 or so days to finish, some shortcuts had to be made. I plan to address the shortcuts and really flesh out the game using it as a vehicle to drive the C++ binding and the ecosystem around it.</p><p>💡 If you’re not looking to make a game but would still like to bind PureScript to C++ code or maybe you’re looking for an alternative to binding Haskell to C++ — no worries — I’ve tried to keep this guide as general as possible.</p><h4>Setting up the Project</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*ILwzJrGwM4JUJClg4ANuZw.jpeg" /></figure><p>Git clone PSN and build it with <a href="https://docs.haskellstack.org/en/stable/README/">stack</a> like you would any other Haskell Stack project.</p><pre>git clone https://github.com/andyarvanitis/purescript-native<br>cd purescript-native<br>stack install<br>cd</pre><p>Once it finishes, you’ll end up with the PureScript to C++ compiler called pscpp. If you stack installed, it should be in your local bin directory. In any case, make sure your path environment variable has the path to pscpp.</p><pre>export PATH=&quot;${PATH}:${HOME}/.local/bin&quot;</pre><p>Next you’ll need Node.js and NPM. I like to manage Node with <a href="https://github.com/creationix/nvm">NVM</a></p><pre>git clone <a href="https://github.com/lettier/lambda-lantern.git">https://github.com/lettier/lambda-lantern.git</a><br>cd lambda-lantern/<br>nvm install `cat .nvmrc` &amp;&amp; nvm use</pre><p>but feel free to use a method you enjoy. Install purescript and psc-package like so.</p><pre>npm install -g purescript psc-package-bin-simple</pre><p>PSN can generate a convenient Makefile that manages the build process. If the Makefile is not already present, go ahead and generate that now.</p><pre>pscpp --makefile</pre><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplayer.vimeo.com%2Fvideo%2F304064252%3Fapp_id%3D122963&amp;dntp=1&amp;url=https%3A%2F%2Fvimeo.com%2F304064252&amp;image=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F743206524_1280.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=vimeo" width="1800" height="1080" frameborder="0" scrolling="no"><a href="https://medium.com/media/d531da815f9849d8c73fdd5dbc0b79ec/href">https://medium.com/media/d531da815f9849d8c73fdd5dbc0b79ec/href</a></iframe><p>Lambda Lantern already has a <a href="https://github.com/lettier/package-sets/tree/lambda-lantern">package set</a> for psc-package. I couldn’t use the <a href="https://github.com/purescript/package-sets">more common one</a> since I needed to include Andy Arvanitis’ <a href="https://github.com/andyarvanitis/purescript-prelude">fork of the prelude</a>. The fork doesn’t rely on the unsafe, implicit-type equality comparisons. Later on, these were removed in version <a href="https://github.com/purescript/purescript-prelude/pull/183">4.1.1</a> of the prelude. This should allow me to use the original ecosystem. Anyway, you can always develop your own package set with psc-package init and pointing the psc-package.json file to your local or remote repository containing your packages.json file.</p><p>Once you have your psc-package.json file ready, install the PureScript dependencies with the following command.</p><pre>psc-package install</pre><p>If you look under .psc-package/ you’ll see all of the PureScript code for your package set but you’re still missing the C++ FFI (foreign function interface).</p><p>Create a ffi/ directory in the main directory of your project. The Makefile that you generated earlier is configured to look there. You can of course change it but be sure to update the Makefile.</p><p>Clone the contents of <a href="https://github.com/andyarvanitis/purescript-native-ffi">purescript-native-ffi</a> into the ffi/ directory.</p><p>⚠️ For <a href="https://github.com/lettier/lambda-lantern">Lambda Lantern</a>, when cloning the FFI repository, be careful not to overwrite any existing files as I had to make some modifications and additions.</p><pre>git clone \<br>  https://github.com/andyarvanitis/purescript-native-ffi.git<br>cp -nr purescript-native-ffi/. lambda-lantern/ffi/</pre><p>Your project directory should look something like this.</p><pre>/<br>  .psc-package/<br>  ffi/<br>  node_modules/<br>  src/<br>    Main.purs<br>  Makefile<br>  psc-package.json</pre><p>At this point you’ll want to install the game engine or C++ code you’ll be binding to. For <a href="https://github.com/lettier/lambda-lantern">Lambda Lantern</a>, you’ll need to <a href="https://www.panda3d.org/download.php?sdk&amp;version=1.9.4">install Panda3D</a>. Panda3D has installers for Linux, macOS, and Windows.</p><h4>Picking the Game Engine</h4><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fg-Aj2h4JhB0%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dg-Aj2h4JhB0&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fg-Aj2h4JhB0%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/24142de0bf1f54d86b2011de2a880cd9/href">https://medium.com/media/24142de0bf1f54d86b2011de2a880cd9/href</a></iframe><p>After reviewing quite a few C++ based game engines, I decided on Panda3D as it had the most straightforward API to bind to. Panda3D comes with most of the functionality you see elsewhere like shaders, particle effects, physics, multiple render targets, 3D audio, etc. Still, if you prefer another engine then feel free to use that one instead. The basic idea to this guide is still applicable.</p><p>A common pattern I noticed in a lot of the engines I reviewed was the need to inherit from some application class. The game engine controls main and calls your filled out application class Hollywood principle style. Having the engine control main would make for an awkward C++ and PureScript sandwich — starting and ending in C++ with the PureScript game logic in the middle. You could, I’m sure, deconstruct the application class and replicate what the engine is doing in main but with Panda3D available, I didn’t see the need.</p><p>The <a href="https://www.panda3d.org/manual/index.php?title=Main_Page&amp;language=cxx">documentation</a> for Panda3D is extensive but sometimes I had to dive into the <a href="https://github.com/panda3d/panda3d">code</a> to find this or that class that didn’t show up in the <a href="https://www.panda3d.org/reference/1.9.4/cxx/annotated">C++ reference</a>. The forums are also a great resource with over a decade of posts to search through. Sometimes you’ll come across outdated solutions so I recommend sorting by recent.</p><h4>Creating the C++ FFI Exports</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*Qg5SGcIqpQiyeoNHFm2MCw.jpeg" /></figure><p>Here is a bare-bones PSN C++ FFI file.</p><pre>#include &quot;purescript.h&quot;</pre><pre>FOREIGN_BEGIN(SomeModuleName)<br>FOREIGN_END</pre><p>Between the foreign begin and end is where you define the exports that are called from the PureScript side.</p><pre>exports[&quot;id&quot;] = [](const boxed&amp; param_) -&gt; boxed {<br>  return param_;<br>};</pre><p>To shuttle around parameters and return values, PSN uses the class boxed. This boxed class builds off of shared_ptr.</p><p>To work with a boxed value, you’ll have to unbox it, providing its type.</p><pre>auto param = unbox&lt;type&gt;(param_);</pre><p>⚠️ If you don’t know the type then you’re stuck. This is the issue with the <a href="https://github.com/purescript/purescript-prelude/blob/0ea05f1140c7b4d9e9847f2ec690fba1f6b2220a/src/Data/Ord/Unsafe.js#L3">implicit-type equality comparisons</a> since the boxed values have their types erased.</p><p>💡 All exports have to accept boxed values and return boxed values. Some types like string, char, double, int, long, etc. can be returned directly. The compiler will construct a boxed value for you since the boxed class comes with a few convenient constructors.</p><pre>exports[&quot;echo&quot;] = [](const boxed&amp; s_) -&gt; boxed {<br>  const auto s = unbox&lt;string&gt;(s_);<br>  return s;<br>}; </pre><p>For other types, you’ll have to call the box procedure to box up your type.</p><pre>exports[&quot;someFunction&quot;] = [](const boxed&amp; param_) -&gt; boxed {<br>  auto param = unbox&lt;Type&gt;(param_);<br>  // ...<br>  return box&lt;Type&gt;(param);<br>};</pre><p>You’ll need to curry your functions or in other words, return a new lambda function for each parameter. If your function returns an Effect, you’ll need an additional lambda function that takes no parameters.</p><p>In PureScript:</p><pre>foreign import add1  :: Number -&gt; Number</pre><pre>foreign import add1&#39; :: Number -&gt; Effect Number</pre><p>In C++:</p><pre>exports[&quot;add1&quot;] = [](const boxed&amp; n_) -&gt; boxed {<br>  const auto n = unbox&lt;double&gt;(n_);<br>  return n + 1.0;<br>};<br>exports[&quot;add1&#39;&quot;] = [](const boxed&amp; n_) -&gt; boxed {<br>  const auto n = unbox&lt;double&gt;(n_);<br>  return [=]() -&gt; boxed {<br>    return n + 1.0;<br>  };<br>};</pre><p>Marking some import with Effect is up to you but generally if the function alters anything outside of its scope or returns different output for the same input, it should use Effect.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*wybb5JyBcVD5WKlv5XoYzA.png" /></figure><p>For those not familar with the syntax up above, PSN exports use C++ lambda functions.</p><pre>[ ] // means don&#39;t capture any external variables.<br>[=] // means capture external variables by value.<br>[&amp;] // means capture external variables by reference.</pre><p>By value means make a duplicate copy of it so any edits to the copy won’t affect the original and by reference means make an alias such that any edits will affect the original. Ideally, you’ll want to use [=] instead of [&amp;] so you don’t alter the input parameters.</p><p>Here’s some typical C++ lambda function patterns.</p><pre>[&amp;capture,=list](p,a,r,a,m,s) -&gt; ReturnType { body; }<br>[&amp;capture,=list](p,a,r,a,m,s)               { body; }<br>[&amp;capture,=list]                            { body; }</pre><p>I believe the best practice is to unbox your parameters as you receive them and use [=] for each returned lambda function like this.</p><pre>[](const boxed&amp; param_) -&gt; boxed {<br>  const auto param = unbox&lt;type&gt;(param_);</pre><pre>  return [=](const boxed&amp; param1_) -&gt; boxed {<br>    const auto param1 = unbox&lt;type&gt;(param1_);</pre><pre>    return [=](const boxed&amp; param2_) -&gt; boxed {<br>      const auto param2 = unbox&lt;type&gt;(param2_);</pre><pre>        return ...<br>    };<br>  };<br>};</pre><p>However, for certain exports, I had to unbox the parameters in the last lambda function only. For example, like <a href="https://gist.github.com/lettier/b536ce03fe5fd46ba5d592e5d812c509#unboxing-in-the-last-lambda-function">this</a>. Unboxing in the first lambda and then copying by reference like <a href="https://gist.github.com/lettier/b536ce03fe5fd46ba5d592e5d812c509#unboxing-in-the-first-lambda-function-and-capturing-by-reference">this</a> caused a segfault. And I couldn’t unbox in the first lambda and then copy by value like <a href="https://gist.github.com/lettier/b536ce03fe5fd46ba5d592e5d812c509#trying-to-mutate-a-constant-nodepath">this</a> as the compiler would complain that I was trying to change a constant NodePath with set_scale. There was the option to use the mutable keyword like <a href="https://gist.github.com/lettier/b536ce03fe5fd46ba5d592e5d812c509#using-the-mutable-keyword">this</a> but unboxing all the parameters in the last lambda function worked fine.</p><p>Another route would’ve been to dynamically allocate node paths —</p><pre>// ...<br>return [&amp;]() -&gt; boxed {<br>  // ...<br>  const auto nodePathPtr = <br>    std::make_shared&lt;NodePath&gt;(<br>      nodePath.find(query)<br>    );<br>  return nodePathPtr;<br>};<br>// ...</pre><p>returning and accepting pointers to them — but this would’ve added unnecessary overhead. Still, with pointers, you can keep them constant, unbox them as soon as you receive them, and copy them by value using [=].</p><p>Generally, I stayed close to the Panda3D API. Ideally you want your exports to be very small and basic — putting any extra logic on the PureScript side for added protection. However, in some cases, I deviated when the procedures were routine and repetitive.</p><p>Binding to some of the Panda3D API wasn’t the only FFI needed. There was also the need to create FFI exports for commonplace functionality like now, JS centric functions like setInterval, requestAnimationFrame, etc., and looking up system environment variables — something completely foreign to JavaScript (in the browser at least).</p><p>💡 Most of the PureScript ecosystem assumes a JavaScript back end which is understandable. Hopefully though, PSN usage grows — increasing with it the C++ FFI coverage. Being able to easily target both the web and native platforms with just PureScript is definitely ideal.</p><p>One particular FFI call was for the browser window, which wasn’t applicable, so I filled it out with a no-op.</p><pre>exports[&quot;window&quot;] = []() -&gt; boxed { return boxed(); };</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*EBjCGSaaV3V4f85pH-d37w.gif" /></figure><p>⚠️ Note that the PSN run time will throw an error if it can’t find the FFI export for some FFI call. If this happens, you’ll see something like the following.</p><pre>terminate called after throwing an instance of<br>&#39;std::runtime_error&#39;</pre><pre>what():  dictionary key &quot;setInterval&quot; not found</pre><p>Obviously it would be great if this was caught at compile time but that may not be feasible.</p><p>I knew I wanted to use <a href="https://medium.com/@lettier/functional-reactive-programming-a0c7b08f6b67">functional reactive programming (FRP)</a> so I needed purescript-behaviors and purescript-event. The former uses requestAnimationFrame while the later uses clearInterval and setInterval.</p><p>Counting down the days to the end of the game jam, I decided to go with a simple multi-threaded model to emulate these JS centric functions in C++. Dealing with multiple threads versus JavaScript’s singled threaded nature, there were some subtle and not so subtle differences to my FRP events.</p><p>In JavaScript this</p><pre>setInterval<br>  ( function () { while (true) { console.log(1); } }<br>  , 1000<br>  );<br>setInterval<br>  ( function () { while (true) { console.log(2); } }<br>  , 1000<br>  );</pre><p>would only ever print 1 over and over, never giving the second interval a chance. But in C++ (using my FFI) something like this</p><pre>setInterval<br>  ( [] { while (true) { std::cout &lt;&lt; 1 &lt;&lt; &quot;\n&quot;; } }<br>  , 1000<br>  );<br>setInterval<br>  ( [] { while (true) { std::cout &lt;&lt; 2 &lt;&lt; &quot;\n&quot;; } }<br>  , 1000<br>  );</pre><p>would print 1 and 2 over and over again concurrently.</p><p>I plan to return to the multi-threaded model and convert it to a single-threaded, non-preemptive priority queue scheduling model to be more like its JavaScript counterpart.</p><h4>Creating the PureScript FFI Imports</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*omZqemJ83GIzYj-U-dcFOQ.jpeg" /></figure><p>The PureScript side of the FFI fence wasn’t all that eventful. Having more time, I would’ve created typeclasses to emulate the class hierarchies found in Panda3D. Now that the game jam is over, I can go through and tidy up the interfaces abstracting out the commonalities.</p><p>Creating the PureScript FFI calls for C++ is the same as it is for JavaScript.</p><p>Here’s an example FFI call to create an ambient light.</p><pre>foreign import data PandaNode :: Type</pre><pre>-- ...</pre><pre>foreign import createAmbientLight<br>  :: String<br>  -&gt; Number<br>  -&gt; Number<br>  -&gt; Number<br>  -&gt; Effect PandaNode</pre><p>This import will call its <a href="https://gist.github.com/lettier/b536ce03fe5fd46ba5d592e5d812c509#creating-an-ambient-light">C++ FFI export</a> counterpart.</p><p>Looking at the pscpp generated C++, you can see how this is eventually hooked together.</p><pre>auto createAmbientLight() -&gt; const boxed&amp; {<br>  static const boxed _ =<br>    foreign().at(&quot;createAmbientLight&quot;);<br>  return _;<br>};</pre><pre>// ...</pre><pre>boxed v27 =<br>  Panda3d::createAmbientLight<br>    ()<br>    (&quot;ambientLight&quot;)<br>    (0.125)<br>    (0.122)<br>    (0.184)<br>    ();</pre><h4>Building the Project</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*CT2y0AvE33lpRWSolMgxLQ.jpeg" /></figure><p>💡 PSN uses the purs compiler (v0.12.0) so there isn’t any difference — PureScript wise — between the C++ and JavaScript targets.</p><p>Here’s the general outline to the build process.</p><ul><li>Compile the PureScript code by calling purs and outputting something called “CoreFn” which is the AST (abstract syntax tree) representation.</li><li>Compile the CoreFn by calling pscpp and outputting C++.</li><li>Compile and link the C++ by calling something like g++ and outputting the final executable.</li></ul><p>Using the generated Makefile makes the build process super easy. It allows you to pass compiler and linker flags if needed. Here’s the make command I use to build Lambda Lantern</p><pre>make \<br>  CXXFLAGS=&quot; \<br>    -fmax-errors=1 \<br>    -I/usr/include/python \<br>    -I/usr/include/panda3d \<br>    -I/usr/include/freetype2&quot; \<br>  LDFLAGS=&quot; \<br>    -L/usr/lib/panda3d \<br>    -lp3framework \<br>    -lpanda \<br>    -lpandafx \<br>    -lpandaexpress \<br>    -lp3dtoolconfig \<br>    -lp3dtool \<br>    -lp3pystub \<br>    -lp3direct \<br>    -pthread \<br>    -lpthread&quot;</pre><p>Most of the flags are to include the Panda3D headers and link against the Panda3D libraries.</p><p>⚠️ /usr/include/python, /usr/include/panda3d, /usr/lib/panda3d, etc. may not be the exact paths for your system. You may also need additional flags not listed up above. For instance, on Ubuntu I have to include -I/usr/include/eigen3 .</p><p>After you build your project, the executable will be located in ./output/bin/.</p><h4>Distributing the Project</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*EntankK12Ny1ZvkrDtw_NA.jpeg" /></figure><p>PSN is cross platform between Linux, macOS, and Windows. For this section, I’ll cover what I did to distribute Lambda Lantern for Linux.</p><p>Having created snaps, flatpaks, AUR packages, and AppImages — I find AppImage to be the best experience for both distributor and user.</p><p>To start, you’ll want to find out what libraries your binary relies on.</p><pre>objdump -p output/bin/main</pre><p>Look for the “Dynamic Section” in the output.</p><pre>Dynamic Section:<br>  NEEDED               libp3framework.so.1.10<br>  NEEDED               libpanda.so.1.10<br>  ...</pre><p>⚠️ You may need additional libraries not listed. And even if you manged to include every single library, your AppImage may not run on older distributions depending on how up-to-date your build environment is (usually due to libc). I recommend using Ubuntu 14.04 or 16.04 as your build environment and then testing your AppImage on as many fresh installations as you can. If you missed any libraries, you’ll receive an error — telling you which library cannot be found — like the following.</p><pre>error while loading shared libraries: libpanda.so.1.10: cannot open shared object file: No such file or directory</pre><p>The nice thing about AppImage is you can include as many or as little libraries as you want. Ideally you’d include any library that isn’t typically found on the average system. This will give your AppImage the greatest chance of working out of the box.</p><p>Here’s the directory tree for the Lambda Lantern AppImage.</p><pre>/<br>  etc/<br>    Confauto.prc<br>    Config.prc<br>  usr/<br>    lib/<br>      panda3d/<br>    share/<br>      applications/<br>        com.lettier.lambda-lantern.desktop<br>      icons/hicolor/256x256/<br>        com.lettier.lambda-lantern.png<br>      lambda-lantern/<br>        assets/<br>          eggs/<br>          fonts/<br>          music/<br>          sounds/<br>      licenses/<br>      metainfo/<br>        com.lettier.lambda-lantern.appdata.xml<br>  AppRun</pre><p>The Config.prc and Confauto.prc files are required for Panda3D to run. In the AppRun file, I provided the path to the prc files and to Lambda Lantern’s assets directory. If you recall, I had to create a FFI export/import for looking up environment variables. At the beginning of the program, Lambda Lantern looks up an environment variable to find its assets.</p><pre>export LAMBDA_LANTERN_ASSETS_PATH=\<br>  &quot;${HERE}/usr/share/lambda-lantern/assets&quot;<br>export PANDA_PRC_DIR=&quot;${HERE}/etc&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*g11vP0abUCpMOHJxrysD3A.gif" /></figure><p>With all of the files in place and the AppRun file filled out, you create the AppImage like so.</p><pre>appimagetool-x86_64.AppImage lambda-lantern.AppDir</pre><p>The AppImage tool will perform some validation and then generate the AppImage if everything checks out.</p><p>If you’re using GitHub, you can upload the AppImage to a release for users to download. After downloading, users can mark the AppImage as executable and start playing! 🎉</p><h4>Final Thoughts</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*_Mbq6maE5E1aUY_hdqvetA.jpeg" /></figure><p>Binding Haskell to C is fairly easy but <a href="https://wiki.haskell.org/Cxx_foreign_function_interface">not so with C++</a>. This is unfortunate as some of the widely used libraries for game development are typically in C++. For awhile I tried various different methods for binding Haskell to C++ but it was never as straightforward as binding PureScript to C++ using PSN. If you’ve found a great way of binding Haskell to complex C++ projects do let me know. However, if you’ve been trying to bind Haskell to C++ — not finding any great options — strongly consider <a href="https://github.com/andyarvanitis/purescript-native">PSN</a>.</p><p>Being able to bind PureScript to C++ opens up so many possibilities since there are so many great <a href="https://en.cppreference.com/w/cpp/links/libs">C++ based projects</a> out there. From cutting edge game engines to robust machine learning libraries. Picking any one of them and gluing on top of it a PureScript interface gives you some distinct advantages.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WMajr9Gt5mbq3ueCnLcFig.png" /></figure><p>Choosing Panda3D, I believe, is the right way forward. It doesn’t try to control the workflow — from concept to executable — making it perfect for me as I enjoy walking untravelled paths, seeing what’s possible like I did with the <a href="https://github.com/lettier/gifcurry">Gifcurry</a> and <a href="https://github.com/lettier/movie-monad">Movie Monad</a> projects. Originally, I wanted to use Godot but I needed it to be something I’d plug in instead of an environment that you augment from inside. If you know of a game that controls main and uses Godot with only C++, please let me know. Anyway, Panda3D is a real gem—dig around a bit you’ll find some great projects using it like the one below.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FUzCIlE7V5UE%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DUzCIlE7V5UE&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FUzCIlE7V5UE%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/c1fd82e62624c0a0f572a9a19f76cc5d/href">https://medium.com/media/c1fd82e62624c0a0f572a9a19f76cc5d/href</a></iframe><p>Hopefully others will use PSN more and more. I’m very excited to turn the concept behind <a href="https://github.com/lettier/lambda-lantern">Lambda Lantern</a> into a full featured game but I’m even more excited about using it to get the word out and build up the ecosystem around PSN. In my opinion, being able to target both the web (JavaScript) and desktop (C++) with ease — using only PureScript— is a dream come true. 👍</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=faabf8f27fe6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Your Easy Guide to Functional Reactive Programming (FRP)]]></title>
            <link>https://medium.com/@lettier/functional-reactive-programming-a0c7b08f6b67?source=rss-dd4eda19e229------2</link>
            <guid isPermaLink="false">https://medium.com/p/a0c7b08f6b67</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Lettier]]></dc:creator>
            <pubDate>Tue, 23 Oct 2018 06:32:07 GMT</pubDate>
            <atom:updated>2019-04-16T01:46:34.635Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Y6Yx5JGK112iqdKMdCtwrA.png" /></figure><p>Managing state. It’s the bane of programmers everywhere. The more stateful processes, subroutines, objects, components, widgets, doodads, etc. there are, the harder it is to keep your app from becoming a giant mud pit.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*bDYbaLP81IRMO3aaDygS8Q.jpeg" /><figcaption>“What, this? No this is nothing. You should see my other code base.”</figcaption></figure><p>But fear not! You can use functional reactive programming (FRP) in your quest to manage state.</p><p>Imagine you have three entities called red, blue, and purple. Your job is to wire them all together such that red + blue = purple. Adjusting red and/or blue should automatically adjust purple.</p><p>Let’s try solving this imperatively and then we’ll switch to FRP.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*C10fTOmhMjbbO7wfv8e4Fg.jpeg" /></figure><p>First, create some objects capable of retaining and manipulating their own state.</p><pre>Color = function() {<br>  this.color = 0;</pre><pre>  this.onChange = function() {};</pre><pre>  this.set = function(color) {<br>    this.color = color;<br>    this.onChange(this.color);};</pre><pre>  this.get = function() {return this.color;};</pre><pre>  this.setOnChange = function(fun) {<br>    this.onChange = fun;}}</pre><pre>red    = new Color();<br>blue   = new Color();<br>purple = new Color();</pre><p>Next, set up the callbacks, wiring them together.</p><pre>red.setOnChange(function(color){<br>  this.purple.set(color + this.blue.get());}.bind(this));</pre><pre>blue.setOnChange(function(color){<br>  this.purple.set(color + this.red.get());}.bind(this));</pre><p>To see what’s going on, set up a logging callback for purple.</p><pre>purple.setOnChange(function(color){<br>  console.log(&quot;Purple: &quot; + color);});</pre><p>And then test it out by changing the state of red and blue.</p><pre>red.set(2);<br>blue.set(4);</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*En3iok8io_Z35tOYDA93ZA.png" /></figure><p>Now let’s switch to FRP.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*JcDo9cICFa-9Jtb2jNZB-Q.jpeg" /></figure><p>First, create the red and blue events.</p><pre>red  &lt;- create<br>blue &lt;- create</pre><p>From those, create some red and blue behaviors.</p><pre>let red&#39;  = step(0)(red.event)<br>let blue&#39; = step(0)(blue.event)</pre><p>And from those behaviors, create the purple behavior.</p><pre>let plus b1 b2 = apply(map(+)(b1))(b2)</pre><pre>let purple = red&#39; `plus` blue&#39;</pre><p>Like before, set up some logging.</p><pre>let log&#39; = log `compose` append(&quot;Purple: &quot;) `compose` show<br>void(animate(purple)(log&#39;))</pre><p>And finally test it out by pushing some values for both red and blue.</p><pre>red.push(2)<br>blue.push(4)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*L0umraFW3Gab8Q4NDGVBlQ.gif" /></figure><p>⚠️ If the FRP version seems completely alien 👽 — don’t worry. By the end you’ll understand it. 😃</p><p>Looking at the two, the FRP version is declarative. You declared or expressed the relationship that purple = red + blue. You gave the what, but not the how. You didn’t have to write any of the plumbing with callbacks. In both cases, whenever red or blue changes — purple changes. So we didn’t lose any functionality by using FRP.</p><h3>What’s functional reactive programming?</h3><blockquote>Functional Reactive Programming, or FRP, is a general framework for programming hybrid systems in a high-level, declarative manner. The key ideas in FRP are its notions of behaviors and events. — <a href="https://dl.acm.org/citation.cfm?id=349299.349331">Zhanyong Wan and Paul Hudak. 2000. Functional reactive programming from first principles.</a></blockquote><p>It wasn’t always called “Functional Reactive Programming,” though. Initially it was called, “Functional Reactive Animation.”</p><blockquote><em>Fran</em> (Functional Reactive Animation) is a collection of data types and functions for composing richly interactive, multimedia animations. The key ideas in Fran are its notions of <em>behaviors</em> and <em>events</em>. — <a href="https://dl.acm.org/citation.cfm?id=258973">Conal Elliott and Paul Hudak. 1997. Functional reactive animation.</a></blockquote><p>Over the years the term has been adopted and used to describe <a href="https://forums.manning.com/posts/list/35838.page">implementations that do not necessarily adhere</a> to the precise mathematical specification or “denotational semantics” as laid out by Conal Elliott and Paul Hudak.</p><p>In any case, true (or what was originally) FRP deals with continuous (versus discrete) time, behaviors, and events. If something is called FRP but doesn’t model time as continuous, doesn’t use behaviors, and/or doesn’t use events then you might consider it, “<a href="https://medium.com/@andrestaltz/why-i-cannot-say-frp-but-i-just-did-d5ffaa23973b">Functional <em>and</em> Reactive Programming (F&amp;RP)</a>.”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*0NJqEgZbFmQJ0H0-tI1DWw.gif" /><figcaption>GIF created with <a href="https://github.com/lettier/gifcurry">Gifcurry</a>.</figcaption></figure><p>To make this concrete, I built a FRP demo called <a href="https://github.com/lettier/purescript-pop">PureScript Pop</a> 💥. Go ahead and have that open while you read along. When you get a chance, take a look at the <a href="https://github.com/lettier/purescript-pop/blob/master/src/Main.purs#L92">source</a> 📜. I made it very readable — even if you’ve never written PureScript before. 👍</p><h3>What’s a behavior?</h3><p>Behaviors are “time-varying values.” A behavior always has a value no matter what time it is and its value may change over time. Give me a point in time, a behavior, and I’ll always have a value for you. Behaviors are continuous variables with respect to time.</p><p>💡 The <a href="http://conal.net/papers/icfp97/icfp97.pdf">simplest behavior is just time itself</a>. You give me a time and I give it right back to you.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*oKRKOonBjugQqnkje6c2eA.png" /></figure><p>Or you can get more complicated like is the mouse button down or up? No matter what the time, the mouse button is either down or up (assuming there’s no in-between transition).</p><pre>let isMouseDown =<br>      step<br>        false<br>        (     (\ {value, buttons} -&gt;<br>                value == 1 &amp;&amp; member 0 buttons)<br>        `map` (withButtons<br>                mouse<br>                (<br>                      ((const 0) `map` up)<br>                `alt` ((const 1) `map` down))))</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*9r2u05zVqizKJercqe0Kgg.png" /></figure><p>So as your application state moves through time, you can always count on behaviors having a value.</p><p>Behaviors get interesting when you combine them to create new behaviors — like combing red with blue to make purple.</p><pre>unfold<br>  (\<br>    { isMouseDown&#39;<br>    , isOverCoin&#39;<br>    , isOverCoinSlot&#39;<br>    }<br>    wasDragging<br>    -&gt;<br>        not isOverCoinSlot&#39;<br>    &amp;&amp;  (   (wasDragging  &amp;&amp; isMouseDown&#39;)<br>        ||  (isMouseDown&#39; &amp;&amp; isOverCoin&#39;)<br>        ))<br>  (sample_<br>    (combine3Behaviors<br>      (Tuple<br>        (SProxy :: SProxy &quot;isMouseDown&#39;&quot;)<br>        isMouseDown)<br>      (Tuple<br>        (SProxy :: SProxy &quot;isOverCoin&#39;&quot;)<br>        isOverCoin)<br>      (Tuple<br>        (SProxy :: SProxy &quot;isOverCoinSlot&#39;&quot;)<br>        isOverCoinSlot))<br>    (interval 1))<br>  false</pre><p>Here I combine three behaviors (isMouseDown, isOverCoin, and isOverCoinSlot) to make a new behavior (isDragging) that lets me know if the mouse is dragging a coin or not.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*2kG9xP-y8veDVGu-WHq7Vg.gif" /><figcaption>GIF created with <a href="https://github.com/lettier/gifcurry">Gifcurry</a>.</figcaption></figure><p>If your programming language has functional programming patterns like <a href="https://medium.com/@lettier/your-easy-guide-to-monads-applicatives-functors-862048d61610">monad, applicative, and functor</a>, your FRP library will typically create instances for monoid, applicative, semigroup, etc. allowing you to easily combine/compose behaviors declaratively.</p><p>Eventually you’ll want to <em>react</em> to a behavior’s value. Your FRP implementation should come with a function that allows you to perform some effectful action over time using the behavior’s value. This effectful action could be updating a button label, moving a game character, logging some information, etc.</p><pre>void $<br>  animate<br>    popMachineState<br>    (coinCursorAnimation<br>      [ coin1Img<br>      , coin2Img<br>      , coin3Img<br>      ])</pre><p>Here I animate the cursor for a coin, depending on the pop machine’s state.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*ujcLWzzAP13bFCamAro6gg.gif" /><figcaption>GIF created with <a href="https://github.com/lettier/gifcurry">Gifcurry</a>.</figcaption></figure><h3>What’s an event?</h3><p>Events are time-stamped values or (time, value) pairs. You give me a time and I… may or may not have a value for you. In other words, events are discrete variables with respect to time.</p><p>💡 The <a href="http://conal.net/papers/icfp97/icfp97.pdf">simplest event is just a constant value at a constant point in time</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*qsDw0HNTVvpLFfykKVglug.png" /></figure><p>But you can get as complex as you like. For example, the location of the mouse at the time of a click.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*uxxf-9_3NgpcYId5ciACwQ.png" /></figure><p>Like behaviors, your FRP library should come with some function that allows you to perform some effectful action, with the event’s value, whenever the event occurs.</p><pre>void $<br>  subscribe<br>    event<br>    (log `compose` show)</pre><h3>How do I create a behavior from an event?</h3><p>FRP gets really interesting when you create behaviors from events and vice versa.</p><pre>let dispensingPopCountEvent = count dispensingPopEvent<br>let dispensedPopCount = step 0 dispensingPopCountEvent</pre><p>From the dispensingPopCountEvent, I create a behavior that always has, as a value, the number of pops given out so far.</p><p>So I go from this…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*dHHUUCdRAwGIcdGwsT_W3w.png" /></figure><p>To this…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*2gAfsaFnHWfqhYVdxNP0jA.png" /></figure><p>Combining this behavior with others, I can determine which pop to animate on the page when the user inserts a coin.</p><pre>case count of<br>  1 -&gt; do<br>    void(goTo(popStop1Div)(functionalPopImg))<br>    void(goTo(popStop2Div)(reactivePopImg))<br>    result &lt;- goTo(popStop3Div)(programmingPopImg)<br>    when result $<br>      popMachine.push(WaitingForPopRemoval)<br>  2 -&gt; -- ...<br>  3 -&gt; -- ...<br>  _ -&gt;<br>    pure(unit)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*uYS6BOm6w1YtyfYFhxJe3Q.gif" /><figcaption>GIF created with <a href="https://github.com/lettier/gifcurry">Gifcurry</a>.</figcaption></figure><h3>How do I create an event from a behavior?</h3><p>Creating events from behaviors opens up a lot of opportunities . Your FRP library should come with functions for turning behaviors into events. One example is the gateBy function.</p><p>Let’s say I wanted to go the other way. I have a behavior that holds how many pops have been dispensed so far. From that, I want an event that holds the pop number being dispensed, every time the machine starts dispensing a pop.</p><pre>let dispensingPopNumber =<br>      gateBy<br>        (\ _ state -&gt; state == DispensingPop)<br>        dispensedPopCount<br>        popMachine.event</pre><p>Using the pop machine event as a trigger, I sample the dispensedPopCount behavior, emitting an event with the behavior’s value whenever the pop machine’s state goes to DispensingPop.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*dLPZuwI5ObuWMOwvVWjOZQ.png" /></figure><h3>How do I combine behaviors?</h3><p>Combining behaviors to make new behaviors is one of the great strengths of FRP.</p><p>Say you have two behaviors, each containing a list of numbers.</p><pre>let behavior1 = step [] event1.event<br>let behavior2 = step [] event2.event</pre><pre>let behavior3 = behavior1 `append` behavior2</pre><pre>void $<br>  animate<br>    behavior3<br>    (log `compose` show)</pre><pre>event1.push [1]<br>event2.push [2]</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/693/1*Uqci5TFXo5XpjPSKTk-zXw.gif" /></figure><p>behavior3 has the value [1,2] and all I had to do was append behavior1 to behavior2.</p><p>Say you have two Boolean behaviors…</p><pre>let behavior3 = (||) `map` behavior1 `apply` behavior2</pre><p>behavior3 is behavior1 or-ed with behavior2 using <a href="https://medium.com/@lettier/your-easy-guide-to-monads-applicatives-functors-862048d61610">functor’s map and applicative’s apply</a>.</p><p>Say you have a string behavior and an integer behavior…</p><pre>let behavior3 =<br>                    (\ string int -&gt;<br>                      string `append` show int)<br>            `map`   behavior1<br>            `apply` behavior2</pre><p>You can come up with all sorts of ways to combine behaviors into what you need.</p><h3>How do I combine events?</h3><p>Like behaviors, you can combine events in similar ways.</p><p>Say you have two events, one and two, and you want another event that occurs whenever one or two occurs.</p><pre>event1 &lt;- create<br>event2 &lt;- create</pre><pre>let event3 = event1.event `alt` event2.event</pre><pre>void $<br>  subscribe<br>    event3<br>    (log `compose` show)</pre><pre>event1.push 1<br>event2.push 2</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*ALPL8mMloAVZcyVbQ9KQbQ.png" /></figure><p>Using alt, I combined event1 and event2 into event3. When either event1 or event2 occurs, event3 occurs.</p><h3>FRP is cool.</h3><p>FRP can be a really powerful way to architect your application using only functions! 🎉 With just behaviors and events, you can declaratively build up a highly stateful application.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*HBfBwHRQ7A_6eNvXgwVj5w.gif" /></figure><p>For another FRP example, head over to <a href="https://lettier.github.io/posts/2016-07-04-haskell-to-javascript.html">Haskell to JavaScript</a> where I build an on/off button using Haskell’s <a href="https://reflex-frp.org/">Reflex</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a0c7b08f6b67" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Your easy guide to Monads, Applicatives, & Functors]]></title>
            <link>https://medium.com/@lettier/your-easy-guide-to-monads-applicatives-functors-862048d61610?source=rss-dd4eda19e229------2</link>
            <guid isPermaLink="false">https://medium.com/p/862048d61610</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[haskell]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[functional-programming]]></category>
            <dc:creator><![CDATA[Lettier]]></dc:creator>
            <pubDate>Thu, 20 Sep 2018 05:33:54 GMT</pubDate>
            <atom:updated>2019-03-09T07:13:33.499Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zGlYj0rUHMSY3ovll0dQDg.png" /></figure><p>Are you curious about monads? 🤔 Or maybe you’re further down the rabbit 🐰 hole, looking into applicatives? Does “functor” sound alien 👽 to you?</p><p>No worries! 😃</p><p>Monad, applicative functor, and functor are just functional programming patterns you can use to deal with effects like lists/arrays, trees, hashes/dictionaries, and even functions.</p><p>Functor is the simplest pattern, so it makes sense to start there. As you work your way to monad, you’ll see that functor is the basis for applicative functor which is the basis for monad.</p><p>⚠️ If you don’t get the animations, don’t worry. Just focus on the code samples and explanations. The animations are there for some visual intuition. 👍</p><h3>What’s a functor?</h3><h4>A functor is a list.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*NE5qp4j6c7nsLI_lvZf_dg.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>map(function)(list) = [function(element) | element &lt;- list]</pre><pre>add1(input) = input + 1</pre><pre>map(add1)([1,2,3])</pre><pre>-- [2,3,4]</pre><p>The list functor takes a function and applies it to every element inside the list. The function doesn’t have to consider or worry about the list — map handles the list.</p><h4>A functor is a function.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*utHwEiIfCvhBveEeABSv9Q.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>map(function1)(function2)(input) = function1(function2(input))<br><br>sub2(input) = input - 2</pre><pre>map(add1)(sub2)(1)<br>-- 0</pre><p>The function functor composes or glues two functions together returning a new function. This new function routes its input through the two functions returning the output of the first function.</p><h4>A functor is a promise.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*AyN3L0kKaCRh5sGfNnEZYg.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>map(function)(promise) = fmap(function)(promise)</pre><pre>promise &lt;- async(return 11)</pre><pre>wait(map(sub2)(promise))<br>-- 9</pre><p>The promise functor applies a function to its fulfilled input and returns a new promise that will contain the output of the function.</p><h4>A functor is an effect that you lawfully define map for.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*lSsTtyaY2_XcyxCnoeNioA.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>map<br>  ::       (input -&gt; output) -- Takes a function.<br>  -&gt; effect(input          ) -- Takes input inside an effect.<br>  -&gt; effect(         output) -- Returns output inside an effect.</pre><p>In general, a functor is just map defined for some effect. The map function</p><ul><li>takes a function input -&gt; output ,</li><li>takes input for that function stuck inside an effect effect(input) ,</li><li>passes the input to the function,</li><li>collects the function’s output,</li><li>and returns the output stuck inside the effect effect(output) .</li></ul><h3>Wait, what do you mean by “lawfully define?”</h3><p>The map definition must obey the functor laws.</p><h4>How many functor laws are there?</h4><p>There are two laws your map definition must obey.</p><h4>Okay, what’s the first law?</h4><p>If you pass identity to map, map’s output must equal its input.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*Xoa27kT2FJ-HBtwsZRFrHg.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>list = [1,2,3]</pre><pre>identity(input) = input</pre><pre>list == map(identity)(list)<br>-- True</pre><h4>Hmm, what’s the second and last law?</h4><p>If you compose two or more functions and pass that to map, map’s output must equal the output of composing multiple calls of map together— one for each function.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*gVhVPPtYrf44OPLpXEdU4A.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>times3(input) = input * 3</pre><pre>composition(input) = add1(sub2(times3(input)))</pre><pre>composition(1)<br>-- 2</pre><pre>list = [1,2,3]</pre><pre>map(composition)(list) == map(add1)(map(sub2)(map(times3)(list)))<br>-- True</pre><p>One call to map using composition and list equaled three calls to map using add1, sub2, and times3 and list.</p><h3>So functor is an interface?</h3><p>Yes. If you define a lawful version of map for some effect, it is an instance of functor or <em>mappable</em>. map is an overloaded function that is defined differently for each type of effect you define it for.</p><p>If you’ve used the usual map for lists/arrays— found in most standard libraries — you’ve been using functors all along. 😺</p><h3>What do you mean by effect?</h3><p>List/Array is an effect. Tuple/Struct/Record is an effect. Future/Promise is an effect. Function is an effect. Tree is an effect. HashMap/Hash/Dictionary is an effect. Maybe/Optional/Nullable is an effect. Either (or the more specialized try) is an effect. There are many effects. These are some of them.</p><p>Ask what an effect is and you’ll see or hear “context”, “functorial context”, “container”, “container and payload”, “wrapper”, “box”, “computation”, “ambiguous computation”, “structures”, “data structures”, “nondeterminism”, “nondeterministic”, “type constructors”, “side-effects”, “a side-effect made explicit”, “impure”, and/or “not pure”. Phew.</p><p>The definition of effect is “power to bring about a result”. This is true for anything I’ve seen called an effect. They <em>have</em> the power or capability to bring about a result but may not always. For example, the empty list/array or nothing/none/null for maybe/optional/nullable.</p><h3>I still don’t get functor.</h3><p>A functor lifts or upgrades a function from one that <strong>cannot</strong> operate on an effect to one that <strong>can</strong> work on a <strong><em>single</em></strong> effect, leaving the effect <strong>intact</strong> after the function is done.</p><p>In terms of an interface, if you want some effect to be a functor, you have to (lawfully) define map for it.</p><h3>Can map accept a function with more than one parameter?</h3><p>If some function takes more than one parameter and you map it over some functor, it will be partially applied and stuck in the effect.</p><p>Take lists for example.</p><pre>add(left)(right) = left + right</pre><pre>map(add)([1,2,3])<br>-- [ add(1),<br>--   add(2),<br>--   add(3) ]</pre><p>add was partially applied to 1, 2, and 3 making for three partial applications of add stuck inside the list. Partially applied meaning the function is waiting on its other parameters. add(1) for example is waiting on one more number.</p><pre>[ add(1),<br>  add(2),<br>  add(3) ]</pre><p>⚠️ At this point you’re stuck. You can’t feed this result back into map in order to supply more input to the adds. map doesn’t take partially applied functions — waiting inside an effect/list — so you’ll need applicative functor to work with this result.</p><h3>What are applicative functors?</h3><h4>An applicative functor is a list.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*Ponp8OKpCXuWwq0nM-QSlw.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>pure(input) = [input]</pre><pre>apply(functions)(list) =<br>  [ element | function &lt;- functions,<br>              element  &lt;- map(function)(list)<br>  ]</pre><pre>apply(pure(add1))([1,2,3])<br>-- [2,3,4]</pre><pre>apply(apply(pure(add))([1,2,3]))([4,5,6])<br>-- [5,6,7,6,7,8,7,8,9]</pre><pre>apply(map(add)([1,2,3]))([4,5,6])        <br>-- [5,6,7,6,7,8,7,8,9]</pre><p>It returns [5, 6, 7, 6, 7, 8, 7, 8, 9] because it adds 1 to 4, 5, and 6, adds 2 to 4, 5, and 6, and then adds 3 to 4, 5, and 6.</p><p>💡 Instead of thinking about a list as a container for values, think of it as a nondeterministic value or put another way, a choice.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*X2sIjCqzsMN4MnBg5KQAwA.gif" /></figure><p>The list applicative functor computes all of the possible combinations or choices when sequencing or composing lists. You can represent this as a tree.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*PZuxWknK1ClEPQ0G46oHYA.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><p>Anyway, notice how I had to use one apply for every parameter add takes. One for the first parameter and another one for the second parameter.</p><p>The pure and first apply call wrapped three partially applied adds inside a list but you can substitute the pure and one apply call with map as using add with map also wraps three partially applied adds inside a list. We saw this up above with functor.</p><pre>apply(pure(add))([1,2,3])<br>-- [ add(1),<br>--   add(2),<br>--   add(3) ]</pre><pre>map(add)([1,2,3])<br>-- [ add(1),<br>--   add(2),<br>--   add(3) ]</pre><p>🤔 So far all of the examples had non-empty lists but what happens if any one list is empty?</p><pre>[   ] `apply` [1,2,3] `apply` [4,5,6]<br>-- []<br>[add] `apply` [     ] `apply` [4,5,6]<br>-- []<br>[add] `apply` [1,2,3] `apply` [     ]<br>-- []</pre><p>You get an empty list. Tracing the implementation, you can see that if any one list is empty, it propagates out. Doesn’t matter what the other lists had, you’ll always get an empty list if any one of the lists are empty.</p><p>If any of the effects are empty or failed, for the list effect and others (like maybe or either), the first occurrence will spill out in the end. This works out nicely as you don’t have to consider the empty case when applying lists or even worse, experience a crash because you ended up with an empty list somewhere.</p><p>💡One of the big aspects of applicative functor is that the effects <em>play out</em> before the lifted/upgraded function can do its thing. Applicative functor is like the Ronco — set it and forget it — showtime rotisserie 🍗 of functional programming patterns. Once we’ve kicked off the process, we can only wait for the end result.</p><p>There’s no picking and choosing what’s next based on what’s already occurred. We don’t get to look at an intermediate result and make a decision. It’s been <a href="https://stackoverflow.com/questions/38707813/parsec-applicatives-vs-monads/38719766#38719766">said</a> that applicative functor is batch versus interactive processing as is the case with monads.</p><p>Let’s say we have a function called if_x_then_y_else_z (example adapted from <em>Applicative Programming with Effects, Conor McBride and Ross Paterson. in Journal of Functional Programming 18:1 (2008), pages 1–13</em>).</p><pre>if_a_then_b_else_c(a)(b)(c) = if a then b else c</pre><pre>pure(if_a_then_b_else_c) `apply` x `apply` y `apply` z</pre><p>It takes in three effects and depending on x’s result, it either picks the result from y or z. Since we’re talking about lists at this point, let’s use the list applicative functor.</p><pre>if_x_then_y_else_z([True])([&quot;y result&quot;])([&quot;z result&quot;])<br>-- [&quot;y result&quot;]</pre><pre>if_x_then_y_else_z([False])([&quot;y result&quot;])([&quot;z result&quot;])<br>-- [&quot;z result&quot;]</pre><p>So if an item of x is True, we go with y’s item else we go with z’s.</p><pre>if_x_then_y_else_z([True])([&quot;y result&quot;])([&quot;z result&quot;])<br>-- [&quot;y result&quot;]</pre><p>For the inputs</p><ul><li>[True]</li><li>[&quot;y result&quot;]</li><li>and [&quot;z result&quot;]</li></ul><p>it doesn’t matter what z holds as it’ll never be used. But notice what happens when z is empty.</p><pre>if_x_then_y_else_z([True])([&quot;y result&quot;])([])<br>-- []</pre><p>You get an empty list even though the z list isn’t needed since x holds a single True. But like I wrote up above, if any of the lists are empty, the result will be empty too.</p><p>You could try to get around this by lifting/upgrading a function that returns a list.</p><pre>if_x_then_y_else_z(x)(y)(z) =<br>  apply(pure(\ a -&gt; if a then y else z))(x)</pre><pre>if_x_then_y_else_z([True])([&quot;y result&quot;])([])                           <br>-- [[&quot;y result&quot;]]</pre><p>⚠️ But now you’re stuck. You have nested effects or in this case, nested lists. Later on, you’ll see how the list monad deals with this situation.</p><p>💡The big thing to remember with applicative functor is that the lifted/upgraded function cannot change/influence the <em>shape</em> of the effect at any time. For list, the shape would be the size. For maybe the shape would be just or nothing. For either the shape would be left or right.</p><p>Without running the applicative functor, you can determine the resulting shape just by looking at the shape of the effects given. Given an empty list? You’re going to get an empty list. Given [1,2] and [3,4,5]? You’re going to get back a list with six items.</p><p>With monads it’s different. They <em>can</em> change the shape because they <em>can</em> look at the intermediate results and decide what to do next.</p><h4>An applicative functor is a function.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*MLWQhRKZEFjpuTZUl60TFg.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>pure(function)(ignore) = function</pre><pre>pure(add1)(Nothing)(0)<br>-- 1</pre><pre>apply(wrapped_function)(function)(input) =<br>  map(wrapped_function(input))(function)(input)</pre><pre>apply(pure(add1))(add1)(1)<br>-- 3</pre><pre>(pure(add) `apply` add1 `apply` add1)(1)<br>-- 4</pre><p>The pure definition for functions is just the constant (const) function. The constant function takes two parameters and returns the first one ignoring the second one. So calling pure(add1)(Nothing) wraps and then unwraps add1. You can unwrap using any input you’d like as constant will just ignore it.</p><pre>pure(add1)(&quot;Ignore this?&quot;)(1)<br>-- 2</pre><pre>pure(add1)(concat [&quot;Ignore&quot;,&quot; this?&quot;])(1)<br>-- 2</pre><p>Notice how I chained as many calls to apply as how ever many parameters the function took. I used one apply for add1 and two calls of apply for add.</p><pre>add_x_y_z(x)(y)(z) = add(add(x)(y))(z)</pre><pre>add_x_y_z(2)(2)(2)<br>-- 6</pre><pre>(pure(add_x_y_z)<br>`apply` add1<br>`apply` add1<br>`apply` add1)(1)<br>-- 6</pre><p>The three calls to apply — one for x, one for y, and one for z — returns 6 because</p><ul><li>1 gets added to 1 making x equal 2</li><li>1 gets added to 1 making y equal 2</li><li>1 gets added to 1 making z equal 2</li><li>and finally x, y, and z get added together for a total of 6.</li></ul><pre>apply(pure(add_x_y_z))(add1)(1)(2)(3)<br>-- 7</pre><pre>add_x_y_z(add1)(2)(3)<br>-- 7</pre><p>You don’t have to chain a call to apply for every argument. In this example, I modified the x parameter with add1 but passed 2 as y and 3 as z directly to add_x_y_z.</p><pre>add1(input) = 1 + input<br>sub2(input) = 2 - input                                 <br>sub3(input) = 3 - input<br>                                 <br>(pure(add_x_y_z) `apply` add1 `apply` sub2 `apply` sub3)(4)<br>-- 2</pre><pre>add1(4) + sub2(4) + sub3(4)<br>-- 2</pre><pre>(1 + 4) + (2 - 4) + (3 - 4)<br>-- 2</pre><p>If you do modify every parameter with apply, the resulting function will only accept one input which will go to every modified parameter. In this example, 2 went to every modified parameter of add_x_y_z.</p><pre>first  = \ (a,b,c) -&gt; a                                                               <br>second = \ (a,b,c) -&gt; b                                                              <br>third  = \ (a,b,c) -&gt; c </pre><pre>new_add_x_y_z =<br>  pure(add_x_y_z) `apply` first `apply` second `apply` third         </pre><pre>new_add_x_y_z(1,2,3)<br>-- 6</pre><p>If the form of your input data doesn’t match the parameter signature of your function, using apply to compose your function with some other functions comes in handy. In this example, the data was in a tuple so I composed add_x_y_z with first, second, and third to extract and then add together 1, 2, and 3.</p><pre>extract_then_add_x_y_z(t) =<br>  add_x_y_z(first(t))(second(t))(third(t))               </pre><pre>extract_then_add_x_y_z(1,2,3)<br>-- 6</pre><p>Granted, I could’ve done it like the example above but applicative functor gives us a nicely generalized interface for modifying the input to some function with other functions.</p><pre>first  = \ (a,b) -&gt; a<br>second = \ (a,b) -&gt; b</pre><pre>new_add_x_y_z = pure(add_x_y_z) `apply` first `apply` second</pre><pre>new_add_x_y_z(1,2)(3)                                         <br>-- 6</pre><p>If say, part of my data was in a tuple, I only have to reason about apply and pure instead of coming up with a specific function to handle this particular scenario.</p><h4>An applicative functor is a functor that you lawfully define pure and apply for.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*rUEGwtrTpeN8p4kVZF-H1A.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>pure<br>  :: input         -- Takes some input.<br>  -&gt; effect(input) -- Returns it inside an effect.</pre><pre>apply<br>  :: effect(input -&gt; output) -- Takes a function in an effect.<br>  -&gt; effect(input          ) -- Takes input in an effect.<br>  -&gt; effect(         output) -- Returns output in an effect.</pre><p>In general, an applicative functor is a functor that you define apply and pure for. The apply function</p><ul><li>takes a function inside an effect effect(input -&gt; output),</li><li>takes input for that function inside an effect effect(input),</li><li>applies the function to the input,</li><li>and returns the function’s output inside the effect effect(output) .</li></ul><p>💡 Compare it to map and you’ll see the subtle change — the function is now in the effect too.</p><pre>map<br>  ::       (input -&gt; output) -- Takes a function.<br>  -&gt; effect(input          ) -- Takes input inside an effect.<br>  -&gt; effect(         output) -- Returns output inside an effect.</pre><pre>apply<br>  :: effect(input -&gt; output) -- Takes a function in an effect.<br>  -&gt; effect(input          ) -- Takes input in an effect.<br>  -&gt; effect(         output) -- Returns output in an effect.</pre><p>👀 Look again but in this condensed form.</p><pre>map   ::  (i -&gt; o) -&gt; e(i) -&gt; e(o)<br>apply :: e(i -&gt; o) -&gt; e(i) -&gt; e(o)<br>--       ^ The big difference.</pre><p>That’s the main and only difference between apply and map .</p><h3>Lawfully, meaning applicative functor has laws too?</h3><p>Yes. There are four applicative functor laws.</p><h3>So applicative functor is an interface too?</h3><p>Yes. If there are lawful definitions of pure and apply for some functor, it is an instance of applicative functor. In other words, applicative functor extends the functor interface with pure and apply.</p><h3>I still don’t get applicative functor.</h3><p>Applicative functor picks up where functor leaves off. Functor lifts/upgrades a function making it capable of operating on a <strong><em>single</em></strong> effect. Applicative functor allows the sequencing of <strong><em>multiple</em></strong> <strong><em>independent</em></strong> effects. Functor deals with one effect while applicative functor can deal with multiple independent effects. In other words, applicative functor generalizes functor.</p><p>In terms of an interface, applicative functor adds pure and apply to functor’s map.</p><h4>What do you mean by independent effects?</h4><p>Independent meaning some effect does not rely on the outcome of some other effect.</p><pre>x = [1,2]<br>y = [3,4]<br>z = [5,6]</pre><pre>pure(add) `apply` (pure(add) `apply` x `apply` y) `apply` z  <br>-- [9,10,10,11,10,11,11,12]</pre><p>In this example, we sequence three effects or lists. Neither x, y, nor z rely on the outcome of any other. Since they’re all independent, we could process the final result in parallel or simultaneously. This is one of the advantages to applicative functor.</p><pre>[ 1+3+5=09,<br>  1+3+6=10,<br>  1+4+5=10,<br>  1+4+6=11,<br>  2+3+5=10,<br>  2+3+6=11,<br>  2+4+5=11,<br>  2+4+6=12 ]</pre><p>Now say we lift/upgrade the following function for the list instance.</p><pre>add1_inside_effect(input) = pure(input + 1)</pre><p>It will return a dependent effect/list dependent on some item input from some other list.</p><pre>pure(add1_inside_an_effect) `apply` x                    <br>-- [[2],[3]]</pre><pre>pure(add) `apply` (pure(add1_inside_an_effect) `apply` x)<br>-- error!</pre><p>Applicative functor only deals with independent effects. If you have a dependent effect, you’ll need monads as you’ll see next.</p><h3>What is a monad?</h3><h4>A monad is a list.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*lo68iv888p4intCkC1W5ig.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>join(nested_lists) =<br>  [element | list &lt;- nested_lists, element &lt;- list]</pre><pre>join([[1], [2, 3], [4, 5, 6]])<br>-- [1, 2, 3, 4, 5, 6]</pre><pre>join(apply(pure(\ x -&gt; [x + 1, 1]), [1,2,3]))<br>-- [2, 1, 3, 1, 4, 1]</pre><pre>join(<br>  apply(<br>    pure(\ x -&gt; [2, x * 3, x * 4]))(<br>    join(<br>      apply(<br>        pure(\ x -&gt; [x + 1, 1]))(<br>        [1,2,3]))))<br>-- [2,6,8,2,3,4,2,9,12,2,3,4,2,12,16,2,3,4]</pre><p>The big and only addition for the monad interface is join. join flattens or better put, peels off an effect from two nested effects. For the list instance, join is just concat.</p><p>Join only deals with nested effects that are the same type and nested one level deep. So for example, [[1], [3,4]], just(just(1)), right(right(2)) but not [just(1), just(left(1))], [1, [2]], [[[1]]], etc.</p><pre>if_x_then_y_else_z =<br>  pure(\ a -&gt; if a then y else z) `apply` x</pre><pre>if_x_then_y_else_z([True])([&quot;y result&quot;])([])                           <br>-- [[&quot;y result&quot;]]</pre><p>When we previously lifted/upgraded a function that returned a list (to get around z being empty), we ended up with a nested list. Back then we were stuck but join allows us to keep on truckin’ 🚚. Now you can pick either the y or z list based on the items in x and <strong><em>not</em></strong> end up with a nested list.</p><pre>if_x_then_y_else_z(x)(y)(z) =<br>  join(pure(\ a -&gt; if a then y else z) `apply` x)</pre><pre>if_x_then_y_else_z(<br>  [True,False,False,True])(<br>  [&quot;y result&quot;])(<br>  [&quot;z result&quot;])<br>-- [ &quot;y result&quot;,  True  so return y.<br>--  &quot;z result&quot;,   False so return z.<br>--  &quot;z result&quot;,   False so return z.<br>--  &quot;y result&quot; ]  True  so return y.</pre><p>💡 Therein lies the power of monads, they allow us to pick the next effect based on the result from a previous effect. In other words, monad allows us to sequence dependent effects or better put, sequence functions that return effects.</p><p>⚠️ Note that “pick the next effect” doesn’t mean you can, at some point, change the type of effect you return. For example, you can’t suddenly decide to return a maybe if you’re operating in the list monad. A monad is also a functor, so in the end, the effect must remain intact with only its results potentially altered.</p><h4>A monad is a function.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*Lo3yqiZcwgr_8XSSZsyJOQ.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>join(wrapped_function)(input) =<br>  wrapped_function(input)(input)</pre><pre>join(apply(pure(add))(add1))(1) <br>-- 3</pre><pre>add(add(1)(1))(1)<br>-- 3</pre><pre>add(2)(1)<br>-- 3</pre><pre>(1 + 1) + 1<br>-- 3</pre><pre>divide(numerator)(denominator) = numerator / denominator</pre><pre>join(<br>  apply(<br>    pure(divide))(<br>    join(<br>      apply(<br>        pure(add))(<br>        add1))))(2)<br>-- 2.5</pre><pre>divide(<br>  add(<br>    add(<br>      1)(<br>      2))(<br>    2))(<br>  2)<br>-- 2.5</pre><pre>divide(<br>  add(<br>    3)(<br>    2))(<br>  2)<br>-- 2.5</pre><pre>divide(<br>  5)(<br>  2)<br>-- 2.5</pre><pre>(((1 + 2) + 2) / 2)<br>-- 2.5</pre><p>The function monad allows you to sequence or compose functions together. The first function in the chain can only take one parameter and the rest have to take two parameters.</p><p>After you’re done composing functions together using join, apply, and pure, the returned function will only take one input. This single input will start a chain reaction.</p><ul><li>The first function takes only one parameter.</li><li>It receives the input and returns some output.</li><li>The second function takes two parameters.</li><li>It receives the output from function one, the input, and returns some output.</li><li>The third function takes two parameters.</li><li>It receives the output from function two, the input, and returns some output.</li><li>The fourth function…and on and on for how ever many functions you sequenced.</li></ul><h4>A monad is an applicative functor that you lawfully define join for.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*f35ZbUkAJPlzeKSqEw-10w.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><pre>join<br>  :: effect(effect(data))<br>  -&gt; effect(data)</pre><p>In general, a monad is just an applicative functor you define join for.</p><h3>So monads are just applicative functors with join added to the interface?</h3><p>Yes.</p><h3>How many laws are there for monad?</h3><p>There are three monad laws.</p><h3>What about return and bind?</h3><p>Bind is just a convenience function that composes join, apply, and pure.</p><pre>bind(effect)(function) = join(apply(pure(function))(effect))</pre><pre>[1,2,3] `bind` \ x -&gt; [x + 2]<br>-- [3,4,5]</pre><pre>[1,2,3] `bind` \ x -&gt; [x + 2] `bind` \ y -&gt; [y * 3]       <br>-- [9,12,15]</pre><pre>[1,2,3] `bind` \ x -&gt; pure(x + 2) `bind` \ y -&gt; [y * 3, 0] <br>-- [9,0,12,0,15,0]</pre><pre>(add1 `bind` add `bind` divide)(2)<br>-- 2.5</pre><p>Or if you prefer, bind composes join and map together.</p><pre>bind(effect)(function) = join(map(function)(effect))</pre><pre>[1,2,3] `bind` \ x -&gt; pure(x + 2) `bind` \ y -&gt; [y * 3, 0] <br>-- [9,0,12,0,15,0]</pre><p>return is just pure.</p><pre>return = pure</pre><h3>Can you summarize them for me?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*kXKjxS87eVC58Rj4KTkWVQ.gif" /><figcaption>Created with Blender and <a href="https://lettier.github.io/gifcurry/">Gifcurry</a>.</figcaption></figure><ul><li>Functor lifts or upgrades a function, allowing it to operate on a single effect, leaving the effect intact after it’s done. It requires a lawful map definition.</li><li>Applicative functor builds on or generalizes functor, allowing you to sequence multiple independent effects. It requires a lawful pure and apply definition.</li><li>Monad builds on or generalizes applicative functor, allowing you to sequence independent and/or dependent effects. It requires a lawful join definition.</li></ul><pre>map   ::  (i -&gt;   o ) -&gt; e(i) -&gt; e(o) -- Functor<br>apply :: e(i -&gt;   o ) -&gt; e(i) -&gt; e(o) -- Applicative<br>bind  ::  (i -&gt; e(o)) -&gt; e(i) -&gt; e(o) -- Monad<br>         ^      ^</pre><p>If you’d like to see what you can do with functors, applicatives, and monads, check out <a href="https://github.com/lettier/movie-monad">Movie Monad</a> and <a href="https://github.com/lettier/gifcurry">Gifcurry</a> — two desktop GUI apps created with Haskell, a purely functional programming language.</p><p>For more information about functors, applicatives, monads, and other functional programming patterns, take a look at <a href="https://wiki.haskell.org/Typeclassopedia">Typeclassopedia by Brent Yorgey</a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=862048d61610" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Style Your GTK App with CSS and Haskell]]></title>
            <link>https://codeburst.io/how-to-style-your-gtk-app-with-css-and-haskell-1aa99c87eb8f?source=rss-dd4eda19e229------2</link>
            <guid isPermaLink="false">https://medium.com/p/1aa99c87eb8f</guid>
            <category><![CDATA[haskell]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[linux]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[html]]></category>
            <dc:creator><![CDATA[Lettier]]></dc:creator>
            <pubDate>Thu, 28 Jun 2018 08:32:58 GMT</pubDate>
            <atom:updated>2018-06-30T09:23:56.033Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1001/1*bQMVkY6PN6I17P6d8P7fOw.png" /></figure><p>For the upcoming release of <a href="https://github.com/lettier/gifcurry">Gifcurry </a>— <a href="https://lettier.github.io/gifcurry/">an open-source, video-to-GIF maker </a>— a completely custom theme was made using CSS and Haskell. The new theme will help maintain a more consistent look and feel across platforms and for Linux — across distros. The theme also ensures the need for only one set of custom icons.</p><p>Creating a GTK desktop app and styling it like you would a web application is a great alternative to frameworks like Electron. You can reuse your CSS knowledge and ship a cross-platform product with reduced system requirements. Of course Haskell isn’t required, as you can create and style GTK apps without it, but why would you want to? 😛</p><blockquote>The CSS-like syntax will hopefully be much more familiar to many people, lowering the barrier for custom theming. — <a href="https://developer.gnome.org/gtk3/stable/gtk-migrating-GtkStyleContext-css.html">https://developer.gnome.org/gtk3/stable/gtk-migrating-GtkStyleContext-css.html</a></blockquote><h4>Supporting Older GTK Versions</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1002/1*aRvb8QscmsbvDprDxGIJcQ.png" /><figcaption>Gifcurry running on Ubuntu 14.04</figcaption></figure><p>When building a custom theme for your GTK application, you’ll have to consider supporting older versions of GTK. If you have Ubuntu 14.04 users for instance, you’ll need to support the GTK 3.10 <a href="https://developer.gnome.org/gtk3/stable/gtk-migrating-GtkStyleContext-css.html">CSS file format</a>. Ubuntu 16.04 users will need support for GTK 3.18.</p><p><a href="https://github.com/lettier/gifcurry">Gifcurry</a> aims to support GTK 3.10 all the way up to <a href="https://blog.gtk.org/2018/06/23/a-gtk-3-update/">GTK 3.24</a> and beyond. Between 3.10 and now, there are some commonalities but big changes occurred in 3.18, 3.19, and 3.20. <a href="https://github.com/lettier/gifcurry">Gifcurry</a> applies a base styling and then detects the machine’s GTK version applying more styling rules as the version number goes higher.</p><p>Some of the big changes include:</p><ul><li>Element selectors like <em>GtkButton</em> turning into<em> button.</em></li><li>Class selectors turning into element selectors like <em>GtkSpinButton .entry</em> turning into <em>spinbutton entry.</em></li><li>Pseudo classes like <em>:insensitive</em> becoming<em> :disabled.</em></li><li>Non-standard properties like <em>-gtk-icon-shadow</em> added in later versions.</li></ul><p>You can combine most of the differences in the same CSS file and there won’t be any conflicts or exceptions raised.</p><pre>entry selection,<br>.entry:selected {<br>  background-color: #000;<br>}</pre><p>GTK will raise exceptions, when parsing your CSS data, for situations like an unknown property or incorrect syntax. This of course doesn’t happen for the web where you browser crashes because of a bad CSS file. Nonetheless, you should test any rules you add. GTK will issue warnings for deprecated rules so be sure to watch the standard streams.</p><h4>Deciding which CSS Rules You Need</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1001/1*_wAkqx6DEG4ld9jsIz3FHA.gif" /></figure><p>There are a lot of elements and states to consider when creating a whole theme. Depending on what widgets you use, you can get away with not specifying everything.</p><p>What I recommended is to select your favorite GTK theme as your system theme. Afterwards, start your app from the terminal specifying you want the interactive debugger.</p><pre>$ GTK_DEBUG=interactive my-gtk-app</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2bDWEuChzgCdFXCEZEzDVQ.png" /></figure><p>This GUI debugger allows you to inspect any element/node and see what its CSS properties, children, parent, style classes, state, and more are. You can change the theme on the fly and also update the CSS rules as the app is running. It is similar to Chrome’s DevTools but you can’t point-and-click update the CSS properties for example. To update the CSS, you’ll have to click the CSS tab and write out your changes in the provided text box. As you write out your rules, it will underline any errors and/or warnings.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*Xd95ZCEs7LS2UJPhxNv7YA.gif" /></figure><p>Using the interactive debugger, you can quickly build up the CSS rules that make up your theme. After you get it looking pixel perfect, select the visual tab and change the theme. Look for any breakages and patch your rules as needed. The more themes you test against, the more your app theme will look consistent no matter what the GTK system theme is.</p><p>After you’re finished with one GTK version, switch to another and continue this same workflow. I like to test GTK 3.22, 3.18, and 3.10 simultaneously using two virtual machines running Ubuntu 14.04 and Ubuntu 16.04.</p><h4>Generating the CSS Data</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*Vrkp1bZEZFUmjxovJUsVYw.gif" /></figure><p>You have a few options for getting the CSS rules to GTK. You can write plain CSS, stick it in a <em>.css</em> file, and apply it via the GTK API.</p><pre>button {<br>   color: white;<br>   background: #000;<br>}</pre><p>…</p><pre>styleFile <br>  &lt;- getDataFileName &quot;data/style.css&quot;</pre><pre>GI.Gtk.cssProviderLoadFromPath<br>  provider<br>  (Data.Text.pack styleFile)</pre><pre>GI.Gtk.styleContextAddProviderForScreen<br>  screen<br>  provider<br>  cssPriority</pre><p>Another option is to use your favorite CSS preprocessor, stick it into your build chain, generate the file, and then apply that via the GTK API. Since we’re using Haskell, we can use <a href="http://fvisser.nl/clay/">Clay</a> — “a CSS preprocessor […] implemented as an embedded domain specific language (EDSL) in Haskell.”</p><p>The nice thing about using Clay is that we don’t have to stick it into the build process, generate a .css file, and load it via the GTK API. Clay allows us to stay in Haskell, generate the CSS rules at run time, and apply the rendered output via <em>cssProviderLoadFromData</em>.</p><pre>let css =<br>        encodeUtf8 $<br>          render $<br>            button ? do<br>              color white<br>              background &quot;#000&quot;</pre><pre>GI.Gtk.cssProviderLoadFromData<br>    provider<br>    css</pre><pre>GI.Gtk.styleContextAddProviderForScreen<br>    screen<br>    provider<br>    cssPriority</pre><h4>The End</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/887/1*A3i-ujPUfWpPsv2oDjRTsw.gif" /></figure><p>If you’ve thought about creating a desktop app, GTK is a great solution that allows fully customizable styling. Using CSS, you’re in complete control of the look, feel, and branding of your app just like you would be with the web. The CSS is slightly different but you’ll hardly notice. And if you need something stronger than styling, you can always <a href="https://codeburst.io/how-to-build-a-custom-gtk-widget-with-haskell-eaff04a6262">create your own custom widget</a>.</p><p>Interested in GTK apps? Take a look at <a href="https://github.com/lettier/movie-monad">Movie Monad</a>. Need a video-to-GIF maker? Download <a href="https://github.com/lettier/gifcurry">Gifcurry</a>. Enjoyed this article? Show your support by clicking the applause button. Thanks!</p><figure><a href="http://bit.ly/codeburst"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*i3hPOj27LTt0ZPn5TQuhZg.png" /></a></figure><blockquote>✉️ <em>Subscribe to </em>CodeBurst’s<em> once-weekly </em><a href="http://bit.ly/codeburst-email"><strong><em>Email Blast</em></strong></a><strong><em>, </em></strong>🐦 <em>Follow </em>CodeBurst<em> on</em><a href="http://bit.ly/codeburst-twitter"><strong><em>Twitter</em></strong></a><em>, view </em>🗺️ <a href="http://bit.ly/2018-web-dev-roadmap"><strong><em>The 2018 Web Developer Roadmap</em></strong></a><em>, and </em>🕸️ <a href="http://bit.ly/learn-web-dev-codeburst"><strong><em>Learn Full Stack Web Development</em></strong></a><em>.</em></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1aa99c87eb8f" width="1" height="1" alt=""><hr><p><a href="https://codeburst.io/how-to-style-your-gtk-app-with-css-and-haskell-1aa99c87eb8f">How to Style Your GTK App with CSS and Haskell</a> was originally published in <a href="https://codeburst.io/">codeburst</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How To Build A Custom GTK Widget With Haskell]]></title>
            <link>https://codeburst.io/how-to-build-a-custom-gtk-widget-with-haskell-eaff04a6262?source=rss-dd4eda19e229------2</link>
            <guid isPermaLink="false">https://medium.com/p/eaff04a6262</guid>
            <category><![CDATA[haskell]]></category>
            <category><![CDATA[front-end-development]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[desktop]]></category>
            <dc:creator><![CDATA[Lettier]]></dc:creator>
            <pubDate>Mon, 18 Jun 2018 05:55:52 GMT</pubDate>
            <atom:updated>2018-06-29T10:04:49.128Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RKmeQDRXqyq1JsuKjOmn1g.png" /></figure><p>GTK, if you’re unfamiliar with it, is a library for creating graphical widgets for the desktop. These widgets can take in user input and/or show application output. GTK comes with a nice selection of widgets. Widgets range from the humble checkbox to a full-blown file explorer. For the most part, you’ll never need to create your own widget but sometimes what’s in stock isn’t enough.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/887/1*A3i-ujPUfWpPsv2oDjRTsw.gif" /></figure><p><a href="https://github.com/lettier/gifcurry">Gifcurry</a> — <a href="https://lettier.github.io/gifcurry">a cross-platform GIF creator slash video editor made with Haskell </a>— needed a custom widget to interface with user selected time slices. There is the main time slice of the GIF and the time slices for each dynamic text overlay added.</p><p>The widget consists of two major areas. The top area shows a zoomed-in view of the GIF time slice itself. The bottom area shows all time slices as they fall between the beginning and end of the video. In both parts, the white line represents the current video’s position. The top part also gets the video position clock. For convenience, the user can click anywhere on the GIF time slice to change the video’s current position. As the input changes, the widget updates to match giving immediate feedback.</p><h4>The Draw Area Widget</h4><p>The draw area widget is the foundation for any fully custom widget.</p><blockquote>The <a href="https://developer.gnome.org/gtk3/stable/GtkDrawingArea.html">GtkDrawingArea</a> widget is used for creating custom user interface elements. It’s essentially a blank widget; you can draw on it. — <a href="https://developer.gnome.org/gtk3/stable/GtkDrawingArea.html">https://developer.gnome.org/gtk3/stable/GtkDrawingArea.html</a></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U-hB28jqAx-eJZGYoXODIA.png" /></figure><p>After you create the draw area, be sure it’s application paintable. Make sure to apply the event masks you wish to capture like a mouse button click.</p><pre>GI.Gtk.widgetAddEvents<br>  myWidget<br>  [GI.Gdk.EventMaskAllEventsMask]</pre><h4>The Draw Widget Queue</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8Q-NM16F6fjFNhxcBdWjzA.png" /></figure><p>GTK takes a lazy approach to drawing widgets. It will redraw your widget when some or all of it has been invalidated like being covered up by another window. To keep a constant render loop going, you’ll have to force a redraw by scheduling it.</p><pre>GI.Glib.timeoutAdd<br>  GI.Glib.PRIORITY_DEFAULT<br>  1 $<br>    GI.Gtk.widgetQueueDraw myWidget<br>    return True</pre><p>Once queued, your widget will receive an <em>onWidgetDraw</em> event. This event is your chance to update any of your widget’s graphics.</p><h4>The On Draw Event</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*8DfX0rlS_qy5YR5-fsJ7Lw.gif" /></figure><p>GTK lets you register a callback for a widget’s <em>onWidgetDraw</em> event. Inside the callback is where you’ll draw on your widget. To draw on your widget, you’ll need another library known as Cairo.</p><blockquote>Cairo is a 2D graphics library with support for multiple output devices. — <a href="https://cairographics.org/">https://cairographics.org/</a></blockquote><p>There are two major Haskell projects that produce bindings for GTK and its related libraries. There is the older one, <a href="https://github.com/gtk2hs/gtk2hs">gtk2hs</a>, and the newer one, <a href="https://github.com/haskell-gi/haskell-gi">haskell-gi</a>. Each comes with its own Cairo binding. For the draw calls, you’ll need the older one (<a href="https://hackage.haskell.org/package/cairo">cairo</a>) provided by gtk2hs.</p><p>The newer binding (<a href="https://hackage.haskell.org/package/gi-cairo">gi-cairo</a>) doesn’t bind to most of the Cairo API as haskell-gi <a href="https://github.com/haskell-gi/haskell-gi/issues/148">generates the binding automatically</a> using <a href="https://wiki.gnome.org/action/show/Projects/GObjectIntrospection?action=show&amp;redirect=GObjectIntrospection">GObject Introspection</a> but the introspection data for <a href="https://cgit.freedesktop.org/cairo/tree/src">Cairo</a> is incomplete. If you do use <a href="https://hackage.haskell.org/package/gi-cairo">gi-cairo</a>, there is a <a href="https://github.com/haskell-gi/haskell-gi/issues/55#issuecomment-246133743">workaround to bridge</a> its binding to the more hand-rolled binding provided by gtk2hs.</p><p>Nevertheless, your registered callback will receive <em>a context</em>. You’ll pass this<em> </em>context off to Cairo and perform all your drawing calls in the <em>Render</em> monad.</p><pre>GI.Gtk.onWidgetDraw<br>  myWidget $<br>    \ context-&gt; do</pre><p>If you want to call something in the IO monad, don’t forget the <em>liftIO</em> function.</p><pre>(r, g, b) &lt;-<br>  liftIO $<br>    getRgb color</pre><p>If you’ve ever done any HTML5 canvas drawing, you’ll be familiar with the context.</p><pre>document.getElementById(&#39;my-canvas&#39;).getContext(&#39;2d&#39;);</pre><p>Relating it to GTK, the <em>GtkDrawingArea</em> is the canvas and the context is…well…the context. Anyway, the context isn’t all that important. It can, however, be a stumbling block when trying to integrate haskell-gi’s gi-cairo with gtk2hs’ cairo.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/807/1*eUIxqIRF8XRBFltoyreTXA.png" /></figure><p>Like the HTML5 canvas API, Cairo comes with all the primitives you’d expect. You can draw lines, rectangles, ellipses, and even text (you’ll need <a href="https://en.wikipedia.org/wiki/Pango">Pango</a> for advanced text rendering). <a href="https://github.com/lettier/gifcurry">Gifcurry</a> uses a PNG pattern fill to color the time slices. The purple area is the GIF time slice and the green is a text overlay time slice.</p><pre>GRC.rectangle x y w h        <br>GRC.setSourceRGBA 0.1 0.1 0.1 1.0<br>GRC.fill</pre><h4>The On Widget Event</h4><p>If your widget is only to show application output, then you’re done at this point and can ship it. If you want to capture user input, you’ll need to register a callback for the event(s) you wish to deal with.</p><pre>GI.Gtk.onWidgetButtonPressEvent<br>  myWidget $<br>    \ eventButton-&gt; do</pre><p><a href="https://github.com/lettier/gifcurry">Gifcurry</a> captures the left mouse button click to update the video’s current position. This allows users to bounce around the video. Using a little algebra and geometry, <a href="https://github.com/lettier/gifcurry">Gifcurry</a> translates the mouse’s 2D spatial coordinates to the video’s 1D time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*n_pZ_dRZRJyD7wGD1B5Neg.gif" /></figure><h4>The End</h4><p>It’s not everyday that someone uses GTK, Haskell, <em>and</em> needs a custom widget. But for those that do, your only limitation now is your imagination. If you only need a <em>slightly</em> modified widget, consider using CSS. <a href="https://medium.com/@lettier/how-to-style-your-gtk-app-with-css-and-haskell-1aa99c87eb8f">GTK widgets can be styled with CSS (just like the web)</a> for a truly custom look. <a href="https://github.com/lettier/gifcurry">Gifcurry</a> uses CSS to style its about dialog.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/738/1*APmn65gJa_PwLdd6SuYCuA.png" /></figure><p>If you haven’t tried GTK but are into native-desktop, front-end development, give it a spin. You can achieve the same look and feel as Electron and spare your users from downloading more RAM. And while you’re at it, give Haskell a try if you haven’t. Haskell works for you so you can spend more time creating great widgets.</p><p>Interested in GTK apps? Take a look at <a href="https://github.com/lettier/movie-monad">Movie Monad</a>. Need a video to GIF maker? Download <a href="https://github.com/lettier/gifcurry">Gifcurry</a>. Enjoyed this article? Clap it up. Thanks!</p><figure><a href="http://bit.ly/codeburst"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*i3hPOj27LTt0ZPn5TQuhZg.png" /></a></figure><blockquote>✉️ <em>Subscribe to </em>CodeBurst’s<em> once-weekly </em><a href="http://bit.ly/codeburst-email"><strong><em>Email Blast</em></strong></a><strong><em>, </em></strong>🐦 <em>Follow </em>CodeBurst<em> on </em><a href="http://bit.ly/codeburst-twitter"><strong><em>Twitter</em></strong></a><em>, view </em>🗺️ <a href="http://bit.ly/2018-web-dev-roadmap"><strong><em>The 2018 Web Developer Roadmap</em></strong></a><em>, and </em>🕸️ <a href="http://bit.ly/learn-web-dev-codeburst"><strong><em>Learn Full Stack Web Development</em></strong></a><em>.</em></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eaff04a6262" width="1" height="1" alt=""><hr><p><a href="https://codeburst.io/how-to-build-a-custom-gtk-widget-with-haskell-eaff04a6262">How To Build A Custom GTK Widget With Haskell</a> was originally published in <a href="https://codeburst.io/">codeburst</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Flatpak a Haskell App into Flathub]]></title>
            <link>https://medium.com/@lettier/how-to-flatpak-a-haskell-app-into-flathub-86ef6d69e94d?source=rss-dd4eda19e229------2</link>
            <guid isPermaLink="false">https://medium.com/p/86ef6d69e94d</guid>
            <category><![CDATA[haskell]]></category>
            <category><![CDATA[linux]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[flatpak]]></category>
            <dc:creator><![CDATA[Lettier]]></dc:creator>
            <pubDate>Sun, 06 May 2018 22:07:12 GMT</pubDate>
            <atom:updated>2018-05-06T22:07:12.093Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sL8LkaWH-xPYv4DchrEFIA.jpeg" /></figure><p>You’ve modeled your life around Kleisli composition. On your right arm is a tattoo that reads, “point free or die.” You can tie the knot in your sleep. Zygohistomorphic prepromorphism is your go-to recursion scheme. You looked out from atop the Haskell pyramid and found the view boring. Now comes the hard part — distributing your Haskell app to Linux users.</p><p>Once that last commit goes in, it’s time to get your app out there by opening up a distribution channel. One viable Linux app distribution channel is <a href="https://flathub.org/home">Flathub</a>.</p><blockquote>Flathub aims to be the place to get and distribute apps for Linux. It is powered by <a href="https://flatpak.org/">Flatpak</a> which allows Flathub apps to run on almost any Linux distribution. — <a href="https://flathub.org/about">https://flathub.org/about</a></blockquote><p>To add your app to Flathub, you must first make a Flatpak manifest. I’ll make this concrete by following along with everyone’s favorite functional video player <a href="https://lettier.github.io/movie-monad">Movie Monad</a> and its induction into <a href="https://flathub.org/home">Flathub</a>.</p><h4>The Setup</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*77MB2qnjLtCxdACFAIduFA.jpeg" /></figure><p>First things first, get a working virtual machine of the latest <a href="https://getfedora.org/en/workstation/download/">Fedora</a> up and running. Geared for Flatpak, Fedora will simplify things.</p><blockquote>While Flatpak is not officially affiliated with the Fedora Project, or GNOME Foundation, it is perhaps best supported by Fedora and the GNOME desktop environment. This is because Fedora releases 23 and later have all had Flatpak in their official repositories. The GNOME Software application also has support for installing Flatpaks. — <a href="https://fedoraproject.org/wiki/Flatpak">https://fedoraproject.org/wiki/Flatpak</a></blockquote><p>With the virtual machine running, make sure you can build and run your Haskell app on Fedora — outside of the Flatpak sandbox system. Identify any issues you come across and any packages you had to install.</p><h4>The Manifest</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WGWqsbjw_p4Psmbi4d3Vxg.jpeg" /></figure><p>The manifest is a JSON file that describes the app, its run time, its permissions, its dependencies, its build procedure, and the command needed to run it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/544/1*o3aAl_jCnHsfMs8M3uKUmA.png" /></figure><p>There are different <a href="http://docs.flatpak.org/en/latest/available-runtimes.html">available run times</a> that come with their own set of packages. Choose the run time that provides the greatest number of dependencies your app needs. For anything needed outside the run time, you’ll have to provide it yourself inside the modules section of the manifest.</p><p>Since we’re dealing with Haskell, you’ll need GHC to build your app inside the sand-boxed build environment. Flatpak doesn’t make any demands about what must be built from source. Flathub, however, does require that you build your app from source.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/849/1*WfZsf-jDiFJ1ixPEWTpS-w.png" /></figure><p>Note the prefix used in the image above. Everything you add to modules should go under “/app”. This is a Flathub rule.</p><p>Inside the sand-boxed build environment, we have no network access. Everything that needs to be downloaded can only be downloaded by flatpak-builder. So anything we want downloaded and available to us inside the sandbox has to go under sources for each module. This makes building Haskell apps much more complicated as it rules out options like Stack or cabal-install.</p><p>To get around the lack of network access, we’ll have to perform some of what Stack and Cabal does. The first thing we need is the list of dependencies we’ll have to download and build. I recommend building your app (outside the Flatpak system) with Cabal — using a fresh sandbox — and making note of which dependencies it builds, their exact version numbers, and <strong>the order it builds them in</strong>.</p><p>The order is important. I don’t know of any Stack or Cabal command that will list the dependencies, with their exact version number, <strong><em>in dependent order</em></strong>. We need the dependencies in order as flatpak-builder runs the modules in the order you list them. If you attempt to build Cabal package B but it depends on A and A is listed below B, B will fail to build and flatpak-builder will exit.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/424/1*pfPb19w-dSLgW-oLLYdkHg.png" /></figure><p>With the list of dependencies (and their version numbers) sorted by dependence, we need to generate the list of modules. We could do this by hand but instead we’ll script it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/664/1*w3OuzUHKU0Knd9MpLvy4Eg.png" /></figure><p>The script up above downloads the dependency from <a href="https://hackage.haskell.org/">Hackage</a>, calculates it hash, and outputs the JSON block to be copied into the manifest for each dependency we feed it. For most Cabal packages, the build commands are the same using the typical setup, configure, build, and install procedure.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/875/1*1knSlZ1uVSNt--4-tLJzEA.png" /></figure><p>For some Cabal packages, you’ll run into <a href="https://hackage.haskell.org/package/old-locale-1.0.0.7/revisions/">revisions</a>. The tar files downloaded from Hackage are not up-to-date with any revisions. In some cases, this will cause the build to break and you’ll have to apply the revisions yourself. You could download the revisions from Hackage (listing the files in the sources section) and overwrite the revised files. Instead, I used sed as you can see in the image above. In this particular case, I had to increase the upper bound limit from &lt;4.9 to &lt;5 for base.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wCU3sbxjVntyG1cAqMnulw.png" /></figure><p>When it comes time to build and install your app, you must copy the AppData, desktop, and icon file into their appropriate places under /app.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1018/1*3Dkx1as-wNHzXdK4ERg_dg.png" /></figure><p>For each file, it must be in reverse domain name notation. So</p><ul><li><strong>my-app.appdata.xml</strong> becomes <strong>tld.domain.my-app.appdata.xml</strong></li><li><strong>my-app.desktop</strong> becomes <strong>tld.domain.my-app.desktop</strong></li><li>and <strong>my-app.svg</strong> becomes <strong>tld.domain.my-app.svg</strong>.</li></ul><p>If your app lives on GitHub, you could use <strong>com.github.username.my-app</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/708/1*97HcdqBBhUaDtzHfgQizEg.png" /></figure><p>Inside the AppData file, the &lt;id/&gt; section must also use the reverse domain name notation. Flathub has a quirk where the &lt;id/&gt; must end in .desktop. If it doesn’t, your app will not show up on the Flathub website but will still appear in GNOME software. Normally, the &lt;id/&gt; section doesn’t need to end with .desktop. I believe this is <a href="https://github.com/flathub/linux-store-backend/commit/24bc353f02cdbe949a051735711502e9dd5d13e5">fixed now</a>, however.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/602/1*BYrA4ZfMvMKWcwLaY2-8gQ.png" /></figure><p>While you’re editing your AppData, run it through appstreamcli validate. This will point out any errors present and make suggestions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/393/1*F1tsSBmM0ljeP7kWwe_B5A.png" /></figure><p>Make sure the Icon= key value entry in the desktop file also uses the reverse domain name notation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/485/1*jsGgZO30KWKCEhuMcerFTA.png" /></figure><p>In the same module block that builds and installs your app, you’ll want to specify a post-install procedure. It is here that you can remove any files not necessary to run your app. This will reduce the final file size making for a quicker download of your app from Flathub.</p><pre>flatpak-builder my-app tld.domain.my-app.json --force-clean --install<br>flatpak run tld.domain.my-app</pre><p>With your manifest complete, it is now time to build and run it. If you need to debug it, you can do the following. This will give you a shell inside the sand-boxed environment.</p><pre>flatpak-builder -- run my-app tld.domain.my-app.json sh</pre><h4>The Pull Request</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ptgOVlAWwj-iST60X0MapQ.jpeg" /></figure><p>You’ve written your manifest and have tested it on your local virtual machine running Fedora. If everything works, you can now fork Flathub and submit your pull request to add your app. Make sure to title the pull request “Adds <em>tld.domain.my-app</em>”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/535/1*MiKy7sGWFNgFQ-zkqGN7dg.png" /></figure><p>After you submit your pull request, the friendly Flathub maintainers will review it, close it, <a href="https://github.com/flathub/com.lettier.movie-monad">open up a repository</a> for it under Flathub, and give you write access to the new repository. With this new repository, you can update the manifest with any version changes necessary. Each time you push to master, a build of your Flatpak will start. Check <a href="https://flathub.org/builds/#/">Buildbot</a> to make sure the build succeeded and deployed.</p><pre>flatpak remote-add flathub https://flathub.org/repo/flathub.flatpakrepo<br>flatpak install flathub tld.domain.my-app</pre><p>Using the commands above, any Flatpak user can now install your app.</p><h4>The End</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HNrWs67VyS4SmEUjEShGTw.jpeg" /></figure><p>As of this writing, I only know of <a href="https://flathub.org/apps/search/haskell">two Haskell apps</a> in Flathub — <a href="https://flathub.org/apps/details/com.lettier.movie-monad">Movie Monad</a> being the more complicated one to build. If you add your Haskell app, be sure to let me know in the comments below.</p><p>Flatpak not your thing? Want to be in more app stores? Check out <a href="https://medium.com/@lettier/how-to-snap-your-awesome-haskell-app-648838d63f09">How to Snap your Awesome (Haskell) App</a>.</p><p>Like Haskell apps? Check out <a href="https://github.com/lettier/gifcurry">Gifcurry</a> and <a href="https://github.com/lettier/movie-monad">Movie Monad</a> — you’ll love ’em.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=86ef6d69e94d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Your Guide to Latent Dirichlet Allocation]]></title>
            <link>https://medium.com/@lettier/how-does-lda-work-ill-explain-using-emoji-108abf40fa7d?source=rss-dd4eda19e229------2</link>
            <guid isPermaLink="false">https://medium.com/p/108abf40fa7d</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[tech]]></category>
            <dc:creator><![CDATA[Lettier]]></dc:creator>
            <pubDate>Fri, 23 Feb 2018 23:32:55 GMT</pubDate>
            <atom:updated>2019-05-31T22:07:32.122Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eqArgnH7PNT76mhB9pQjIg.jpeg" /><figcaption>Not too many stock photos for “Latent Dirichlet Allocation”.</figcaption></figure><p>Before we get started, I made a <a href="https://lettier.com/lda-topic-modeling/">tool</a> (here’s the <a href="https://github.com/lettier/lda-topic-modeling">source</a>) that runs LDA right inside your browser (it’s pretty neat). Be sure to have that open as I go along, it will make things a lot clearer.</p><p>All of the emoji I use come from this <a href="https://eosrei.github.io/emojione-color-font/full-demo.html">page</a>. Just select any one emoji and copy it into the input boxes. If you don’t see the emoji, try using <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> version 50 or greater.</p><h4>What is LDA?</h4><p>Latent Dirichlet Allocation (LDA) is a “generative probabilistic model” of a collection of composites made up of parts. Its uses include<a href="https://en.wikipedia.org/wiki/Natural-language_processing"> Natural Language Processing (NLP)</a> and <a href="https://en.wikipedia.org/wiki/Topic_model">topic modelling</a>, among others.</p><p>In terms of topic modelling, the composites are documents and the parts are words and/or phrases (phrases <em>n</em> words in length are referred to as n-grams).</p><p>But you could apply LDA to DNA and nucleotides, pizzas and toppings, molecules and atoms, employees and skills, or keyboards and crumbs.</p><p>The probabilistic topic model estimated by LDA consists of two tables (matrices). The first table describes the probability or chance of selecting a particular part when sampling a particular topic (category).</p><p>The second table describes the chance of selecting a particular topic when sampling a particular document or composite.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tmmF-dCMjvASOrGuwxJN9w.png" /><figcaption>I suddenly have a taste for bacon avocado toast.</figcaption></figure><p>Take the image up above for example. We have four emoji sequences (the ‘composites’) and three types of emoji (the ‘parts’).</p><p>The first three documents have ten of only one type of emoji, while the last document has ten of each type.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*f7ODdUPZtkcWUNcT0CJDzw.png" /><figcaption>X marks the bacon.</figcaption></figure><p>After we run our emoji composites through LDA, we end up with the probabilistic topic model you see above.</p><p>The left table has ‘emoji-versus-topics’, and the right table shows ‘documents-versus-topics’. Each column in the left table and each row in the right table sums to one (allowing for some truncation and precision loss).</p><p>So if I were to sample (draw an emoji out of a bag) Topic 0, I’d almost certainly get the avocado emoji. If I sampled Document 3, there’s an equal (or ‘uniform’) probability I’d get either Topic 0, 1, or 2.</p><p>The LDA algorithm assumes your composites were generated like so:</p><ol><li>Pick your unique set of parts.</li><li>Pick how many composites you want.</li><li>Pick how many parts you want per composite (sample from a Poisson distribution).</li><li>Pick how many topics (categories) you want.</li><li>Pick a number between not-zero and positive infinity and call it <em>alpha</em>.</li><li>Pick a number between not-zero and positive infinity and call it <em>beta</em>.</li><li>Build the ‘parts-versus-topics’ table. For each column, draw a sample (spin the wheel) from a <a href="https://en.wikipedia.org/wiki/Dirichlet_distribution">Dirichlet distribution</a> (which is a distribution of distributions) using <em>beta</em> as the input. Each sample will fill out each column in the table, sum to one, and give the probability of each part per topic (column).</li><li>Build the ‘composites-versus-topics’ table. For each row, draw a sample from a Dirichlet distribution using <em>alpha</em> as the input. Each sample will fill out each row in the table, sum to one, and give the probability of each topic (column) per composite.</li><li>Build the actual composites. For each composite, 1) look up its row in the ‘composites-versus-topics’ table, 2) sample a topic based on the probabilities in the row, 3) go to the ‘parts-versus-topics’ table, 4) look up the topic sampled, 5) sample a part based on the probabilities in the column, 6) repeat from step 2 until you’ve reached how many parts this composite was set to have.</li></ol><p>Now we know this algorithm (or generative procedure/process) is not how documents (such as articles) are written, but this — for better or worse — is the simplified model LDA assumes.</p><h4>What is the Dirichlet distribution?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*_NdnljMqi8L2_lAYwH3JDQ.gif" /><figcaption>Good ol’ matplotlib.</figcaption></figure><p>A bit about the Dirichlet distribution before we move on.</p><p>What you see in the animation above are iterations of taking 1000 samples from a Dirichlet distribution using an increasing <em>alpha</em> value.</p><p>The Dirichlet distribution takes a number (called <em>alpha</em> in most places) for each topic (or category). In the GIF (and for our purposes), every topic is given the same <em>alpha</em> value you see displayed. Each dot represents some distribution or mixture of the three topics like (1.0, 0.0, 0.0) or (0.4, 0.3, 0.3). Remember that each sample has to add up to one.</p><p>At low <em>alpha</em> values (less than one), most of the topic distribution samples are in the corners (near the topics). For really low <em>alpha</em> values, it’s likely you’ll end up sampling (1.0, 0.0, 0.0), (0.0, 1.0, 0.0), or (0.0, 0.0, 1.0). This would mean that a document would only ever have one topic, if we were building a three topic probabilistic topic model from scratch.</p><p>At <em>alpha</em> equal to one, any space on the surface of the triangle (or if you prefer, ‘2-simplex’) is fair game (in other words, uniformly distributed). You could equally likely end up with a sample favoring only one topic, a sample that gives an even mixture of all the topics, or something in between.</p><p>For <em>alpha</em> values greater than one, the samples start to congregate in the center of the triangle. This means that as <em>alpha</em> gets bigger, your samples will more likely be uniform — that is, represent an even mixture of all the topics.</p><p>The GIF demonstrates the sampling of topic mixtures for the documents, but the Dirichlet distribution is also assumed the source (the <a href="https://en.wikipedia.org/wiki/Prior_probability">Bayesian prior</a>) for the mixture of parts per topic.</p><p>Three topics were used, as that works well when plotting in three dimensions. But typically, it is better to use more than three topics, depending on the number of documents you have.</p><p>If you look at the <a href="https://lettier.com/lda-topic-modeling/">LDA tool</a> mentioned earlier, you’ll see an <em>alpha</em> and <em>beta</em> slider.</p><p>These two <a href="https://en.wikipedia.org/wiki/Hyperparameter_(machine_learning)">hyperparameters</a> are required by LDA. The <em>alpha</em> controls the mixture of topics for any given document. Turn it down, and the documents will likely have less of a mixture of topics. Turn it up, and the documents will likely have more of a mixture of topics.</p><p>The <em>beta</em> hyperparameter controls the distribution of words per topic. Turn it down, and the topics will likely have less words. Turn it up, and the topics will likely have more words.</p><p>Ideally, we want our composites to be made up of only a few topics and our parts to belong to only some of the topics. With this in mind, <em>alpha</em> and <em>beta</em> are typically set below one.</p><h4>Why use LDA?</h4><p>If you view the number of topics as a number of clusters and the probabilities as the proportion of cluster membership, then using LDA is a way of soft-clustering your composites and parts.</p><p>Contrast this with say, k-means, where each entity can only belong to one cluster (hard-clustering). LDA allows for ‘fuzzy’ memberships. This provides a more nuanced way of recommending similar items, finding duplicates, or discovering user profiles/personas.</p><blockquote>You could analyze every GitHub repository’s topics/tags and infer themes like native desktop client, back-end web service, single-paged app, or flappy bird clone.</blockquote><p>If you choose the number of topics to be less than the documents, using LDA is a way of reducing the dimensionality (the number of rows and columns) of the original composite versus part data set.</p><p>With the documents now mapped to a lower dimensional latent/hidden topic/category space, you can now apply other machine learning algorithms which will benefit from the smaller number of dimensions. For example, you could run your documents through LDA, and then hard-cluster them using <a href="https://www.naftaliharris.com/blog/visualizing-dbscan-clustering/">DBSCAN</a>.</p><p>Of course, the main reason you’d use LDA is to uncover the themes lurking in your data. By using LDA on pizza orders, you might infer pizza topping themes like ‘spicy’, ‘salty’, ‘savory’, and ‘sweet’.</p><p>You could analyze every GitHub repository’s topics/tags, and infer themes like ‘native desktop client’, ‘back-end web service’, ‘single paged app’, or ‘flappy bird clone’.</p><h4>How does LDA work?</h4><p>There are a few ways of implementing LDA. Still, like most — if not all — machine learning algorithms, it comes down to estimating one or more parameters.</p><p>For LDA, those parameters are <em>phi</em> and <em>theta</em> (although sometimes they’re called something else). <em>Phi</em> is the ‘parts-versus-topics’ matrix, and <em>theta</em> is the ‘composites-versus-topics’ matrix.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*szc1yRtfebCezMRsN4UWaA.png" /><figcaption>Are you more a cat or dog person?</figcaption></figure><p>To learn how it works, let’s walk through a concrete example.</p><p>The documents and emojis are shown in the image above.</p><p>Our hyperparameters are:</p><ul><li><em>alpha</em> = 0.5</li><li><em>beta</em> = 0.01</li><li>‘topics’ = 2</li><li>‘iterations’ = 1.</li></ul><p>The following manual run-through is based on the academic paper <a href="http://173.236.226.255/tom/papers/SteyversGriffiths.pdf">‘Probabilistic Topic Models’</a><em> </em>by Steyvers &amp; Griffiths.</p><p>Instead of estimating <em>phi</em> and <em>theta</em> directly, we will estimate the topic assignments for each of the four emoji using the <a href="http://www.mit.edu/~ilkery/papers/GibbsSampling.pdf">Gibbs sampling algorithm</a>. Once we have the estimated topic assignments, we can then estimate <em>phi</em> and <em>theta</em>.</p><p>To start, we need to randomly assign a topic to each emoji. Using a fair coin (sampling from a uniform distribution), we randomly assign to the first cat emoji ‘Topic 0’, the second cat ‘Topic 1’, the first dog emoji ‘Topic 1’, and the second dog ‘Topic 0’.</p><pre>|         | Cat 0 | Cat 1 | Dog 0 | Dog 1 |<br>|---------|-------|-------|-------|-------|<br>| Topic 0 | *     |       |       | *     |<br>| Topic 1 |       | *     | *     |       |</pre><p>This is our current topic assignment per each emoji.</p><pre>|     | Topic 0 | Topic 1 |<br>|-----|---------|---------|<br>| Cat | 1       | 1       |<br>| Dog | 1       | 1       |</pre><p>This is our current emoji versus topic counts.</p><pre>|            | Topic 0 | Topic 1 |<br>|------------|---------|---------|<br>| Document 0 | 1       | 1       |<br>| Document 1 | 1       | 1       |</pre><p>This our current document versus topic counts.</p><p>Now we need to update the topic assignment for the first cat. We subtract one from the emoji versus topic counts for Cat 0, subtract one from the document versus topic counts for Cat 0, calculate the probability of Topic 0 and 1 for Cat 0, flip a biased coin (sample from a categorical distribution), and then update the assignment and counts.</p><pre>t0 =<br>(<br>  (cat emoji with Topic 0 + beta)<br>  /<br>  (emoji with Topic 0 + unique emoji * beta)<br>)<br>*<br>(<br>  (emoji in Document 0 with Topic 0 + alpha)<br>  /<br>  (emoji in Document 0 with a topic + number of topics * alpha)<br>) =<br>(<br>  (0 + 0.01)<br>  /<br>  (1 + 2 * 0.01)<br>)<br>*<br>(<br>  (0 + 0.5)<br>  /<br>  (1 + 2 * 0.5)<br>) = 0.0024509803921568627</pre><pre>t1 = ((1 + 0.01) / (2 + 2 * 0.01)) * ((1 + 0.5) / (1 + 2 * 0.5))<br>   = 0.375</pre><pre>p(Cat 0 = Topic 0 | *) = t0 / (t0 + t1) = 0.006493506493506494<br>p(Cat 0 = Topic 1 | *) = t1 / (t0 + t1) = 0.9935064935064936</pre><p>After flipping the biased coin, we surprisingly get the same Topic 0 for Cat 0 so our tables before updating Cat 0 remain the same.</p><p>Next we do for Cat 1 what we did for Cat 0. After the flipping the biased coin, we get Topic 0 so now our tables look like so.</p><pre>|         | Cat 0 | Cat 1 | Dog 0 | Dog 1 |<br>|---------|-------|-------|-------|-------|<br>| Topic 0 | *     | *     |       | *     |<br>| Topic 1 |       |       | *     |       |</pre><p>This is our current topic assignment per each emoji.</p><pre>|     | Topic 0 | Topic 1 |<br>|-----|---------|---------|<br>| Cat | 2       | 0       |<br>| Dog | 1       | 1       |</pre><p>This is our current emoji versus topic counts.</p><pre>|            | Topic 0 | Topic 1 |<br>|------------|---------|---------|<br>| Document 0 | 2       | 0       |<br>| Document 1 | 1       | 1       |</pre><p>This our current document versus topic counts.</p><p>What we did for the two cat emoji we now do for the dog emoji. After flipping the biased coins, we end up assigning Topic 1 to Dog 0 and Topic 1 to Dog 1.</p><pre>|         | Cat 0 | Cat 1 | Dog 0 | Dog 1 |<br>|---------|-------|-------|-------|-------|<br>| Topic 0 | *     | *     |       |       |<br>| Topic 1 |       |       | *     | *     |</pre><p>This is our current topic assignment per each emoji.</p><pre>|     | Topic 0 | Topic 1 |<br>|-----|---------|---------|<br>| Cat | 2       | 0       |<br>| Dog | 0       | 2       |</pre><p>This is our current emoji versus topic counts.</p><pre>|            | Topic 0 | Topic 1 |<br>|------------|---------|---------|<br>| Document 0 | 2       | 0       |<br>| Document 1 | 0       | 2       |</pre><p>This our current document versus topic counts.</p><p>Since we’ve completed one iteration, we are now done with the Gibbs sampling algorithm and we have our topic assignment estimates.</p><p>To estimate <em>phi</em>, we use the following equation for each row-column cell in the ‘emoji-versus-topic’ count matrix.</p><pre>Phi row column =<br>  (emoji row with topic column + beta)<br>  /<br>  (all emoji with topic column + unique emoji * beta)</pre><p>And for estimating <em>theta,</em> we use the following equation for each row-column cell in the document versus topic count matrix.</p><pre>Theta row column =<br>  (emoji in document row with topic column + alpha)<br>  /<br>  (emoji in document row + number of topics * alpha)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7ompnTE6eiH_3CitGvtveQ.png" /><figcaption>Stylish styling brought to you by Bulma.</figcaption></figure><p>At long last we are done. The image above contains the estimated <em>phi</em> and <em>theta</em> parameters of our probabilistic topic model.</p><p>The matrix on the left shows us that the cat emoji is much, much more likely to represent Topic 0 than Topic 1, and that the dog emoji is much more likely to represent Topic 1 than Topic 0.</p><p>The matrix on the right shows us that Document 0 is more likely to be about Topic 0 than Topic 1, and that Document 1 is more likely to be about Topic 1.</p><p>This is how LDA can be used to classify documents (composites) and words/n-grams (parts) into topics.</p><p>If you enjoyed this article, you might also like <a href="https://lettier.github.io/posts/2016-04-24-k-means-from-scratch.html">Boost your skills, how to easily write K-Means</a>, <a href="https://lettier.github.io/posts/2016-06-10-k-nearest-neighbors-from-scratch.html">k-Nearest Neighbors from Scratch</a>, and <a href="https://lettier.github.io/posts/2017-01-15-linear-regression-and-the-amazing-beard.html">Let’s make a Linear Regression Calculator with PureScript</a>.</p><p>How have you used LDA? Do you prefer Gensim or MALLET? How cool would it be if Elasticsearch did topic modeling out of the box? Let me know in the responses below. Thanks!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=108abf40fa7d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Snap your Awesome Haskell App]]></title>
            <link>https://medium.com/@lettier/how-to-snap-your-awesome-haskell-app-648838d63f09?source=rss-dd4eda19e229------2</link>
            <guid isPermaLink="false">https://medium.com/p/648838d63f09</guid>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[haskell]]></category>
            <category><![CDATA[linux]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[ubuntu]]></category>
            <dc:creator><![CDATA[Lettier]]></dc:creator>
            <pubDate>Mon, 12 Feb 2018 04:06:18 GMT</pubDate>
            <atom:updated>2018-06-08T04:36:23.507Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KYVwb9Dr5vamk3GAJJzjkw.jpeg" /></figure><p>There comes a time in most every app’s life when it needs distribution. If you can, it’s best to ship it in as many ways as possible. Still, if you’re targeting Ubuntu—or Linux in general — a decent solution is to create a snap.</p><h4>What is a snap?</h4><p>According to the Snapcraft website, “Snaps are universal Linux packages.” The end user goal is to provide a no-hassle way to download software and keep it up to date as new revisions come out. No building, compiling, transpiling, linking, making, make installing, and/or dependency downloading — just download the snap and you’re off to the races.</p><h4>So how do I get started snapping my app?</h4><p>I recommend firing up a <a href="https://medium.com/@tushar0618/install-ubuntu-16-04-lts-on-virtual-box-desktop-version-30dc6f1958d0">virtual machine running Ubuntu 16.04</a> even if you use Ubuntu as your daily driver. This will give you a clean slate and you’ll have the most documentation/support at your disposal.</p><p>Before we continue, I’ll make this concrete by going over what it took to snap <a href="https://github.com/lettier/movie-monad">Movie Monad</a> — a mildly-popular Haskell app. For another example, checkout <a href="https://snapcraft.io/gifcurry">Gifcurry</a>, a great Haskell app that converts videos to GIFs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*Y_uDJFp6zqMzd321T4ro0w.gif" /></figure><p>With the virtual machine up, you’ll need to install <em>snapcraft</em> and everything needed to run its <em>cleanbuild</em> command. You could do away with the clean build approach but this will help you work out the kinks faster and keep your build nice and well…clean. I once failed the linting process because a stray Vim .<em>swp</em> file found its way into the final <em>squashFS</em> file system.</p><pre>mkdir -p ~/my-snap-builds/my-app/snap/gui<br>sudo apt install snapcraft lxd lxd-client<br>sudo usermod -a -G lxd myusername<br>sudo lxd init<br>cd ~/my-snap-builds/my-app<br>snapcraft init</pre><p>If everything went to plan, you should end up with a directory structure like this.</p><pre>~/<br>  my-snap-builds/<br>    my-app/<br>      snap/<br>        gui/<br>        snapcraft.yaml</pre><p>If it is a GUI app, you’ll want to place a <a href="https://developer.gnome.org/integration-guide/stable/desktop-files.html.en">.desktop file</a> and icon under <em>gui/</em>.</p><h4>How do I fill out the snapcraft.yaml file?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*ckYksvan5VDdeCKsd2GyCQ.gif" /></figure><p>The first entries of the file are the <a href="https://github.com/lettier/movie-monad/blob/9dcdc8ace054e93740506dec25015779b784858c/packaging/linux/snap/snapcraft.yaml#L1">metadata</a> for use in the snap store. I recommend a snappy summary since this is all they’ll have to go on when searching the snap store.</p><pre>snap search movie-monad<br># Name         Version  Developer  Notes  Summary<br># movie-monad  0.0.4.0  lettier    -      A free and simple to use video player built with Haskell.</pre><p>The grade must be stable to release the snap into the stable channel. Once you figure out what permissions or “<a href="https://docs.snapcraft.io/core/interfaces">plugs</a>” your app will need, make sure to set the confinement to strict.</p><p>After the metadata, there are two major sections — the <em>apps</em> and the <em>parts</em>. For <a href="https://lettier.github.io/movie-monad">Movie Monad</a>, there’s only one app. The command subsection contains a “<a href="https://insights.ubuntu.com/2016/07/06/ubuntu-app-developer-blog-announcing-new-snap-desktop-launchers/">desktop launcher</a>” which is a convenience wrapper provided by the Snapcraft team. If your app is GTK or QT based, be sure to look into it.</p><p>The <a href="https://lettier.github.io/movie-monad">Movie Monad</a> <em>snapcraft.yaml</em> file has two major <em>parts</em>. There is the <a href="https://lettier.github.io/movie-monad">Movie Monad</a> build/install part and the <a href="https://github.com/Ubuntu/snapcraft-desktop-helpers/blob/2ecb9b320a149293fbe5e76d18213d67eb629658/snapcraft.yaml#L176">desktop-gtk3</a> part which sets up the GTK+ desktop environment. The Snapcraft team provides the<em> desktop-gtk3</em> part. I list it under <em>after</em> informing the Snapcraft build system to create that part after the <a href="https://lettier.github.io/movie-monad">Movie Monad</a> part.</p><p>If your app has a standard build and install process (./configure, make, make install) then you can use a <a href="https://docs.snapcraft.io/build-snaps/plugins">plugin</a>. I’ve deviated from the norm, so instead of a plugin, I created my own <em>scriplets</em>.</p><blockquote>Scriptlets are shell scripts sourced directly from your snapcraft.yaml, to change the behaviour of a plugin. — <a href="https://docs.snapcraft.io/build-snaps/scriptlets">https://docs.snapcraft.io/build-snaps/scriptlets</a></blockquote><p>The most elaborate <em>scriptlet</em> is the install one. In this <em>scriplet</em>, I take the output files from <em>cabal</em> and move them all over to the install directory. It is the install directory that the Snapcraft build system will squash into a snap file.</p><p>Backing up a bit, you’ll see a list of <em>build-packages</em> and <em>stage-packages</em>. The build packages are the software you’ll need to build your app’s executable file(s). The stage packages are more than likely the run-time dependencies your app needs. The build packages do not make it into the final snap file — so if you only need it to build — do not list it under stage packages.</p><p><a href="https://lettier.github.io/movie-monad">Movie Monad</a> uses the <a href="https://docs.haskellstack.org/en/stable/README/">Haskell Stack</a> build tool to make the build process as reproducible as possible. Unfortunately, the resulting executable is not all that <a href="https://github.com/commercialhaskell/stack/issues/848">relocatable</a> or portable. Portable meaning you can move the build directory around and the app will still run. Snapcraft recommends that your app be relocatable.</p><blockquote>The main concept to snap your software is that your application needs to be relocatable. It’s a good practice to not rely on hard coded paths like /etc and such, but to read your assets, configuration, hooks from subdirectories of your application. — <a href="https://docs.snapcraft.io/snaps/philosophy">https://docs.snapcraft.io/snaps/philosophy</a></blockquote><p>Having the build be portable is important since <a href="https://lettier.github.io/movie-monad">Movie Monad</a> relies on <a href="https://www.haskell.org/cabal/users-guide/developing-packages.html#pkg-field-data-files">data files</a> at run time. So to have both a reproducible and relocatable build, <a href="https://lettier.github.io/movie-monad">Movie Monad</a> uses both <a href="https://github.com/lettier/movie-monad/blob/9dcdc8ace054e93740506dec25015779b784858c/makefile#L14">Stack and Cabal</a>. After the build scriptlet finishes, the <em>.cabal-sandbox</em> directory is created and its contents are relocated into the <a href="https://github.com/lettier/movie-monad/blob/9dcdc8ace054e93740506dec25015779b784858c/packaging/linux/snap/snapcraft.yaml#L190">install scriptlet</a>.</p><p>With your <em>snapcraft.yaml</em> file done, run the clean build command.</p><pre>cd ~/my-snap-builds/my-app<br>snapcraft cleanbuild<br>ls<br># my-app_version_arch.snap my-app_version_source.tar.bz2 snap/</pre><h4>How do I get my snap into the snap store?</h4><p>With your snap built, you’ll need to <a href="https://dashboard.snapcraft.io/snaps/">setup an account</a> if you haven’t already.</p><pre>cd ~/my-snap-builds/my-app<br>snapcraft login<br>snap login myusername@myemailprovider.com<br>snapcraft register my-app<br>snapcraft push my-app_version_arch.snap<br>snapcraft release my-app 1 stable</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*oCvadTiwfyUBKzBariFjDg.gif" /></figure><p>And with that, you’ve snapped your awesome Haskell app!</p><h4>What snags, if any, did you run into?</h4><p>The snapping process came together well. I did run into a bug with the Snapcraft site when trying to undo a revoked name. I had deleted my yet unreleased snap which locked me out of the name — don’t do that. The moderator <a href="https://forum.snapcraft.io/u/noise/summary">noise</a>, from the forums, was very helpful and recovered the name for me.</p><p>The snap itself does have some issues that are not present in a regular build of <a href="https://lettier.github.io/movie-monad">Movie Monad</a>. If you run the executable out of the sandbox, all the issues go away. Based on this, the sandboxing has some issues that need work.</p><h4>Where can I find more information about Snapcraft?</h4><p>For more information head over to the <a href="https://docs.snapcraft.io/">Snapcraft</a> site and be sure to make a stop at the <a href="https://forum.snapcraft.io/">forums</a>. The community there is very helpful.</p><p>How do you use snap? What apps have you snapped? Do you like Flatpak, Snapcraft, or AppImage better? What Haskell apps do you enjoy? Let me know in the responses below. Thanks!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=648838d63f09" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Text Analysis of Death Row Prior Occupations]]></title>
            <link>https://medium.com/@lettier/text-mining-in-r-death-row-prior-occupations-by-david-lettier-fc0726bd4b3?source=rss-dd4eda19e229------2</link>
            <guid isPermaLink="false">https://medium.com/p/fc0726bd4b3</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[death-penalty]]></category>
            <category><![CDATA[data-mining]]></category>
            <category><![CDATA[prison]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Lettier]]></dc:creator>
            <pubDate>Wed, 17 Feb 2016 00:00:00 GMT</pubDate>
            <atom:updated>2018-02-24T05:20:02.113Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*C_nOQwBpDpOjCzU99PsiPw.jpeg" /></figure><p>Found in a list of <a href="http://rs.io/100-interesting-data-sets-for-statistics/">100+ interesting data sets</a>, the <a href="http://www.tdcj.state.tx.us/death_row/index.html">Texas Department of Criminal Justice</a> provides different collections of information on death row inmates both present and past. Prior occupations for each current offender are listed <a href="http://www.tdcj.state.tx.us/death_row/dr_offenders_on_dr.html">here</a>.</p><h3>Dependencies</h3><p>We’ll need some packages to scrape, cluster, and chart our findings.</p><ul><li><a href="https://cran.r-project.org/web/packages/rvest/rvest.pdf">rvest</a>: “Wrappers around the ‘xml2’ and ‘httr’ packages to make it easy to download, then manipulate, HTML and XML.”</li><li><a href="https://cran.r-project.org/web/packages/wordcloud/wordcloud.pdf">wordcloud</a>: “Pretty word clouds.”</li><li><a href="https://cran.r-project.org/web/packages/tm/tm.pdf">tm</a>: “A framework for text mining applications within R.”</li><li><a href="https://cran.r-project.org/web/packages/apcluster/apcluster.pdf">apcluster</a>: “The ‘apcluster’ package implements Frey’s and Dueck’s Affinity Propagation clustering in R.”</li></ul><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1d72698638a8c05ac4e7b9c30507f030/href">https://medium.com/media/1d72698638a8c05ac4e7b9c30507f030/href</a></iframe><h3>Collection</h3><p>The data we wish to look at is not in the form we need it. We’ll need to capture the HTML and parse it looking for the prior occupation information. Using rvest, we will grep for all &lt;p&gt; tags that contain the occupation information. Not every page is consistent so we will need some logic to hunt around for the prior occupation field. Once we’ve parsed every page, all of the raw information will be saved to a CSV file for later pre-processing. Each line corresponds to each death row inmate prior occupations collected.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9fb4389c38b83570cda78ce220cfbfbf/href">https://medium.com/media/9fb4389c38b83570cda78ce220cfbfbf/href</a></iframe><h3>Pre-processing</h3><p>With the CSV file opened, we need to clean each entry for unwanted white-space and punctuation. For those with multiple prior occupations, we’ll split on the commas. Once cleaned, we’ll add each prior occupation per inmate to the inmates_occupations list.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5315c331ead23b75638bc145ce0d4dab/href">https://medium.com/media/5315c331ead23b75638bc145ce0d4dab/href</a></iframe><p>Looking over the dataset, you’ll notice some redundancies such as mechanic versus auto mechanic. With care, we will condense the prior occupations to the sub-strings of the redundancies. We’ll also need to hard-code some corrections for irregularities such as fork lift versus forklift. Once the duplicates have been merged, we’ll generate a unique list of the prior occupations for our axis labels.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/58f2669e868c1b8b1c63d54c6a2635d9/href">https://medium.com/media/58f2669e868c1b8b1c63d54c6a2635d9/href</a></iframe><h3>Mining</h3><p>We have collected, cleaned, and removed erroneous variations in our dataset. Now we’ll move on to mining and plotting/charting our data.</p><h3>Total Prior Occupation Relative Frequency Distribution</h3><p>Let us begin by charting the relative frequency of prior occupations listed across all sampled inmates.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/60ad67930e04f53785a88425f011c774/href">https://medium.com/media/60ad67930e04f53785a88425f011c774/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8qK9Advuw1buANHveMop0A.png" /><figcaption>Prior Occupation Relative Frequency Distribution of 182 Texas Death Row Inmates</figcaption></figure><p>The unique prior occupations are in alphabetical order along the x-axis. The y-axis is the relative frequency distribution. laborer accounts for nearly 41% of the 291 listed prior occupations among the 182 death row inmates sampled. Attributing to its large percentage was the merging of duplicates, for example, general laborer and assembly line laborer into just laborer. One could argue that they are distinct labels. construction and none are the second and third largest respectively.</p><p>We can explore the dataset further by clustering the sampled inmates by the prior occupations they had. We’ll treat each inmate as a document with their prior occupations making up the document. By clustering the inmates via their prior occupations, we can partition the dataset into different prior occupation profiles.</p><h3>Inmate Prior Occupations Matrix</h3><p>To begin clustering, we will need to vectorize each inmates’ prior occupations. We’ll assemble these vectors, into the inmate_matrix_count where [i][j] is &gt;= 1 if the i-th inmate had the j-th occupation and zero otherwise. No inmate had the same prior occupation listed more than once, so no count will be greater than one.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f69996824cea0af3750a786fa42a1054/href">https://medium.com/media/f69996824cea0af3750a786fa42a1054/href</a></iframe><h3>Prior Occupation Weighting (TF-IDF)</h3><p>Since we are dealing with text and that nearly half of all sampled inmates were a laborer at some point, we’ll perform a term weighting technique known as <a href="https://en.wikipedia.org/wiki/Tf%E2%80%93idf">TF-IDF</a>. Given that an inmate was both a laborer and welder at some point, TF-IDF will weight laborer less since welder appears less frequently in the text corpus. Knowing that an inmate was a laborer does not <em>say</em> as much as knowing they were also a welder.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/13c69e2ca0e664ddd18b7ba776415b20/href">https://medium.com/media/13c69e2ca0e664ddd18b7ba776415b20/href</a></iframe><h3>Multidimensional Scaling (MDS)</h3><p>To visualize the inmate vectors in two dimensions we’ll employ <a href="https://en.wikipedia.org/wiki/Multidimensional_scaling">multidimensional scaling</a>.</p><blockquote><em>An MDS algorithm aims to place each object in N-dimensional space such that the between-object distances are preserved as well as possible. — Multidimensional Scaling, Wikipedia, the free encyclopedia</em></blockquote><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/20c7ded5bb9c2a2bba9e54b0a631aa5e/href">https://medium.com/media/20c7ded5bb9c2a2bba9e54b0a631aa5e/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*BcQ11YHkehqxXZ9D.png" /><figcaption>Inmate Prior Occupation 2D Visualization (TFIDF-MDS)</figcaption></figure><p>We can see a large mass around the origin. Another distinct mass is seen at (-0.8951273 -0.702121).</p><h3>Affinity Propagation (AP) Clustering</h3><p>Due to the concave shapes and variable density of the MDS scatter plot, we’ll employ <a href="https://en.wikipedia.org/wiki/Affinity_propagation">Affinity Propagation Clustering</a>. This has the added benefit of not having to specify the amount of clusters ahead of time (K).</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5e745450ec57acdf5cac0ff1ffac674f/href">https://medium.com/media/5e745450ec57acdf5cac0ff1ffac674f/href</a></iframe><p>With the inmate_matrix_tfidf_mds clustered, we can now plot the clusters.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e37f1408ba1767fc1b61ed8e44a3c7bc/href">https://medium.com/media/e37f1408ba1767fc1b61ed8e44a3c7bc/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Pd4zoyPqvgkLcy8w.png" /><figcaption>Death Row Inmate Clustering by Prior Occupations (TFIDF-MDS-AP)</figcaption></figure><p>In total, the algorithm generated 17 clusters. Cluster membership sizes range from one to 92 inmates.</p><h3>Inmate Clusters, Prior Occupations Relative Frequency Distributions</h3><p>Now let us generate a relative frequency distribution bar-chart for each TF-IDF MDS AP cluster.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1d76027feacff0bd843cd1b6db978c51/href">https://medium.com/media/1d76027feacff0bd843cd1b6db978c51/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*HgDIwFBN5e-w6v3z.png" /><figcaption>Prior Occupation Relative Frequency Distribution of 15 Texas Death Row Inmate(s) for Cluster 1 (TFIDF-MDS-AP)</figcaption></figure><p>Cluster 1, seen at (-0.8951273 -0.702121), is solely comprised of none which agrees with the dataset. Intuitively, if an inmate had no prior occupations, you wouldn’t expect to see other prior occupation terms clustered with none.</p><p>The following bar-charts are the clusters making up the large mass centered around the origin.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*pcNfwJRPl6CJalWG.png" /><figcaption>Prior Occupation Relative Frequency Distribution of 92 Texas Death Row Inmate(s) for Cluster 5 (TFIDF-MDS-AP)</figcaption></figure><p>Cluster 5 accounts for the inmates that were mainly laborers with only a very few having one other prior occupation. This cluster also contains a large portion of the unique prior occupations found in the raw data set such as computer software.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5VkBlFxHKIAY7COi.png" /><figcaption>Prior Occupation Relative Frequency Distribution of 13 Texas Death Row Inmate(s) for Cluster 10 (TFIDF-MDS-AP)</figcaption></figure><p>For cluster 10, there is a large mixture of both laborer and warehouse.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*UimS4GTA6PuAhYDc.png" /><figcaption>Prior Occupation Relative Frequency Distribution of 14 Texas Death Row Inmate(s) for Cluster 17 (TFIDF-MDS-AP)</figcaption></figure><p>Cluster 17 is more difficult to interpret and could have been likely clustered with cluster 5, however, it is the only cluster that accounts for the inmates that had unknown prior occupations. unknown did not collocate with any other prior occupation so it is surprising to find it clustered with other prior occupations. This is likely due to the MDS.</p><h3>Automatic Cluster Labels</h3><p>Using <a href="https://en.wikipedia.org/wiki/Cluster_labeling#Differential_cluster_labeling">differential cluster labeling</a> and more specifically <a href="https://en.wikipedia.org/wiki/Cluster_labeling#Pointwise_mutual_information">pointwise mutual information (PMI)</a>, we can label each cluster according to its prior occupation with the highest association.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/14ddda97f5dfc9c643c324b169971ecd/href">https://medium.com/media/14ddda97f5dfc9c643c324b169971ecd/href</a></iframe><ul><li>Cluster 1: none</li><li>Cluster 2: mechanic</li><li>Cluster 3: mechanic</li><li>Cluster 4: construction</li><li>Cluster 5: laborer</li><li>Cluster 6: cook</li><li>Cluster 7: welder</li><li>Cluster 8: welder</li><li>Cluster 9: ac</li><li>Cluster 10: warehouse</li><li>Cluster 11: construction</li><li>Cluster 12: clerk</li><li>Cluster 13: shipping</li><li>Cluster 14: clerk</li><li>Cluster 15: welder</li><li>Cluster 16: mechanic</li><li>Cluster 17: unknown</li></ul><p>Condensing these even further:</p><ol><li>none: cluster 1</li><li>mechanic: cluster 2, 3, 16</li><li>construction: cluster 4, 11</li><li>laborer: cluster 5</li><li>cook: cluster 6</li><li>welder: cluster 7, 8, 15</li><li>ac: cluster 9</li><li>warehouse: cluster 10</li><li>clerk: cluster 12, 14</li><li>shipping: cluster 13</li><li>unknown: cluster 17</li></ol><p>This effectively condenses down the original 60 prior occupations down to the 11 most prominent in the sampled data. These 11 prior occupations could all be described as <a href="https://www.opm.gov/policy-data-oversight/data-analysis-documentation/federal-employment-reports/reports-publications/the-twenty-largest-blue-collar-occupations/">blue-collar occupations</a> with the exception of clerk.</p><h3>TF-IDF AP Clustering Only</h3><p>Comparing the TF-IDF MDS AP clusters to TF-IDF AP clusters, using only the inmate_matrix_tfidf, the Affinity Propagation clustering algorithm generated 48 clusters using the original 60 dimensions versus the 17 clusters generated using the two dimensions found by MDS.</p><p>These 48 clusters are more granular with a clearer partitioning of inmates with unique prior occupations. 30 out of the 48 clusters contain only one inmate due to their unique combination of prior occupations. Cluster membership ranges from one to 71. Like with the MDS clusters, none is its own cluster. However, unlike the MDS clusters, all of the unknown prior occupations are clustered together alone.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*vMKIAKyTTUjl-Heq.png" /><figcaption>Prior Occupation Relative Frequency Distribution of 6 Texas Death Row Inmate(s) for Cluster 47 (TFIDF-AP)</figcaption></figure><h3>Latent Semantic Indexing (LSI), Singular Value Decomposition (SVD)</h3><p>We can take the TF-IDF normalized inmate-prior-occupation matrix and perform <a href="https://en.wikipedia.org/wiki/Latent_semantic_indexing#Rank-reduced_singular_value_decomposition">SVD</a> on it.</p><blockquote><em>LSI can be viewed as soft clustering by interpreting each dimension of the reduced space as a cluster and the value that a document has on that dimension as its fractional membership in that cluster. — </em><a href="http://nlp.stanford.edu/IR-book/html/htmledition/latent-semantic-indexing-1.html"><em>Introduction to Information Retrieval</em></a></blockquote><p>This will give us three matrices U, D, and V. U contains our inmate-concept vectors in the new orthogonal basis.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0f8a9e6fe0cb582bb6b9ca22cd86f51a/href">https://medium.com/media/0f8a9e6fe0cb582bb6b9ca22cd86f51a/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*vyk4lxtb1JNJhUyI.png" /><figcaption>SVD Singular Values</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*pZ8KJF3ALcK79ZLK.png" /><figcaption>SVD Explained Variance</figcaption></figure><p>We’ll need to choose a K &lt;= R (R being the <a href="https://en.wikipedia.org/wiki/Rank_(linear_algebra)">rank</a>) where R=60. At K=38, 90% of the variability of the original matrix is explained.</p><p>Now let us cluster and plot the prior occupation relative frequency distribution for each resulting cluster.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ed4b3f22d81b5aa0db7ad4be9110c633/href">https://medium.com/media/ed4b3f22d81b5aa0db7ad4be9110c633/href</a></iframe><p>After clustering, 40 clusters were found. Contrast this with the 48 found by TF-IDF alone which used 60 features instead the 38 used after applying SVD. Cluster membership ranges from one to 71.</p><p>Below are the cluster labels found by PMI:</p><ul><li>Cluster 1: computer operator</li><li>Cluster 2: none</li><li>Cluster 3: kitchen worker</li><li>Cluster 4: computer programmer</li><li>Cluster 5: construction</li><li>Cluster 6: warehouse</li><li>Cluster 7: landscaper</li><li>Cluster 8: cabinet maker</li><li>Cluster 9: sales</li><li>Cluster 10: pipe fitter</li><li>Cluster 11: laborer</li><li>Cluster 12: barber</li><li>Cluster 13: machine operator</li><li>Cluster 14: truck driver</li><li>Cluster 15: oil field</li><li>Cluster 16: food service</li><li>Cluster 17: roofer</li><li>Cluster 18: fabricator</li><li>Cluster 19: cook</li><li>Cluster 20: computer technician</li><li>Cluster 21: janitor</li><li>Cluster 22: wrecker driver</li><li>Cluster 23: painter</li><li>Cluster 24: hydro-water blaster</li><li>Cluster 25: ranch hand</li><li>Cluster 26: heavy equipment operator</li><li>Cluster 27: iron worker</li><li>Cluster 28: shipping</li><li>Cluster 29: computer software</li><li>Cluster 30: clerk</li><li>Cluster 31: plumber’s helper</li><li>Cluster 32: welder</li><li>Cluster 33: mechanic</li><li>Cluster 34: carpenter</li><li>Cluster 35: forklift</li><li>Cluster 36: heating</li><li>Cluster 37: unkown</li><li>Cluster 38: food service</li><li>Cluster 39: jewelry designer</li><li>Cluster 40: ac</li></ul><h3>Wrap-up</h3><p>We collected, parsed, and mined the prior occupations of current death row inmates. Interesting patterns discovered were the large portion of blue-collar occupations (most notably laborer) and more rare prior occupations such as computer operator and jewelry designer. An interesting hypothesis test would be the correlation between being on death row and having been a laborer. The SVD computation could be used for information retrieval allowing one to search for similar current inmates by some prior occupation query. Further analysis could include plotting the amount of each prior occupation seen per year.</p><h3>Appendix</h3><h4>Full SVD AP Clustering</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9163b9e7b20a6db57394daa71180865e/href">https://medium.com/media/9163b9e7b20a6db57394daa71180865e/href</a></iframe><h4>Full Source Code</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1d93cf935f68a2249588d5258e780c98/href">https://medium.com/media/1d93cf935f68a2249588d5258e780c98/href</a></iframe><p><em>Originally published at </em><a href="http://lettier.github.io/posts/2016-02-17-text-mining-in-r-death-row-prior-occupations.html"><em>lettier.github.io</em></a><em> on February 17, 2016.</em></p><blockquote>Find more at <a href="http://www.lettier.com/">Lettier</a>, <a href="https://lettier.github.io/">Blog</a>, <a href="https://twitter.com/lettier">Twitter</a>, <a href="https://github.com/lettier">Github</a>, and <a href="https://www.linkedin.com/in/lettier">LinkedIn</a>.</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fc0726bd4b3" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>