her.esy.fun/src/Scratch/en/blog/Haskell-Tutorials--a-tutorial/index.html

366 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>YBlog - Haskell Tutorials, a tutorial</title>
<meta name="keywords" content="programming, tutorial, haskell, documentation" />
<link rel="shortcut icon" type="image/x-icon" href="../../../../Scratch/img/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/css/y.css" />
<link rel="stylesheet" type="text/css" href="/css/legacy.css" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="apple-touch-icon" href="../../../../Scratch/img/about/FlatAvatar@2x.png" />
<!--[if lt IE 9]>
<script src="http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js"></script>
<![endif]-->
<!-- IndieAuth -->
<link href="https://twitter.com/yogsototh" rel="me">
<link href="https://github.com/yogsototh" rel="me">
<link href="mailto:yann.esposito@gmail.com" rel="me">
<link rel="pgpkey" href="../../../../pubkey.txt">
</head>
<body lang="en" class="article">
<div id="content">
<div id="header">
<div id="choix">
<span id="choixlang">
<a href="../../../../Scratch/fr/blog/Haskell-Tutorials--a-tutorial/">French</a>
</span>
<span class="tomenu"><a href="#navigation">↓ Menu ↓</a></span>
<span class="flush"></span>
</div>
</div>
<div id="titre">
<h1>Haskell Tutorials, a tutorial</h1>
</div>
<div class="flush"></div>
<div id="afterheader" class="article">
<div class="corps">
<div>
<img src="../../../../Scratch/img/blog/Haskell-Tutorials--a-tutorial/main.jpg" alt="Main image" />
</div>
<div class="intro">
<p><span class="sc"><abbr title="Too long; didn't read">tl;dr</abbr>: </span> Some hints on how to make great documentation for Haskell libraries.</p>
<ol type="1">
<li>Create a <code>Tutorial</code> module containing nothing except documentation.</li>
<li>Mention the <code>Tutorial</code> module in your <code>cabal</code> description</li>
<li>Use <code>doctest</code> to check your documentation is up to date</li>
<li>For more complex real world examples, link to the source of some test.</li>
</ol>
</div>
<p>Great documentation make a big difference. A bad documentation could simply make people not using your lib.</p>
<p>My friend was learning Haskell. To start he tried a Haskell library to make a small application. The documentation was deprecated to the point he wasnt able to make a basic example work. How do you believe he felt? What does he thought about Haskell in general?</p>
<p>So here are my hint on how to make a great documentation in Haskell.</p>
<p>Documentation can take many different form.</p>
<ol type="1">
<li><strong>Tutorials/Guides</strong> write some prose which friendly take a user by hand and help him</li>
<li><strong>Examples</strong> how to use each function</li>
<li><strong>Generated API Documentation</strong> haddock</li>
</ol>
<h2 id="hints">Hints</h2>
<h3 id="tutorialsguides">Tutorials/Guides</h3>
<ol type="1">
<li>Create a new module named <code>Tutorial</code> (or <code>Guide.GuideTopic</code>)</li>
<li>Create a link to the tutorial in the cabal description</li>
<li>Create a link to the tutorial in your README</li>
<li>Here is an example some <code>Tutorial</code> module content:</li>
</ol>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb1-1" title="1"><span class="ot">{-# OPTIONS_GHC -fno-warn-unused-imports #-}</span></a>
<a class="sourceLine" id="cb1-2" title="2"><span class="co">{-|</span></a>
<a class="sourceLine" id="cb1-3" title="3"><span class="co"> Use @my-package@ if you want to ...</span></a>
<a class="sourceLine" id="cb1-4" title="4"><span class="co">-}</span></a>
<a class="sourceLine" id="cb1-5" title="5"><span class="kw">module</span> <span class="dt">Data.Duration.Tutorial</span> (</a>
<a class="sourceLine" id="cb1-6" title="6"></a>
<a class="sourceLine" id="cb1-7" title="7"> <span class="co">-- * Introduction</span></a>
<a class="sourceLine" id="cb1-8" title="8"> <span class="co">-- $introduction</span></a>
<a class="sourceLine" id="cb1-9" title="9"></a>
<a class="sourceLine" id="cb1-10" title="10"> <span class="co">-- ** Subsection</span></a>
<a class="sourceLine" id="cb1-11" title="11"> <span class="co">-- $subsection</span></a>
<a class="sourceLine" id="cb1-12" title="12"></a>
<a class="sourceLine" id="cb1-13" title="13"> ) <span class="kw">where</span></a>
<a class="sourceLine" id="cb1-14" title="14"></a>
<a class="sourceLine" id="cb1-15" title="15"><span class="kw">import</span> <span class="dt">Data.Duration</span></a>
<a class="sourceLine" id="cb1-16" title="16"></a>
<a class="sourceLine" id="cb1-17" title="17"><span class="co">{- $introduction</span></a>
<a class="sourceLine" id="cb1-18" title="18"></a>
<a class="sourceLine" id="cb1-19" title="19"><span class="co">So here how you use it:</span></a>
<a class="sourceLine" id="cb1-20" title="20"></a>
<a class="sourceLine" id="cb1-21" title="21"><span class="co"> &gt;&gt;&gt; humanReadableDuration 1002012.002</span></a>
<a class="sourceLine" id="cb1-22" title="22"><span class="co"> &quot;11 days 14 hours 20 min 12s 2ms&quot;</span></a>
<a class="sourceLine" id="cb1-23" title="23"></a>
<a class="sourceLine" id="cb1-24" title="24"><span class="co">The function is 'humanReadableDuration' and</span></a>
<a class="sourceLine" id="cb1-25" title="25"><span class="co">the you'll be able to click on it to go</span></a>
<a class="sourceLine" id="cb1-26" title="26"><span class="co">to its definition.</span></a>
<a class="sourceLine" id="cb1-27" title="27"></a>
<a class="sourceLine" id="cb1-28" title="28"><span class="co">You can add images: &lt;&lt;path-to-image.png title&gt;&gt;</span></a>
<a class="sourceLine" id="cb1-29" title="29"><span class="co">and links: &lt;http://haskell-lang.org haskell&gt;.</span></a>
<a class="sourceLine" id="cb1-30" title="30"><span class="co"> </span></a>
<a class="sourceLine" id="cb1-31" title="31"><span class="co">-}</span></a>
<a class="sourceLine" id="cb1-32" title="32"></a>
<a class="sourceLine" id="cb1-33" title="33"><span class="co">{- $subsection</span></a>
<a class="sourceLine" id="cb1-34" title="34"></a>
<a class="sourceLine" id="cb1-35" title="35"><span class="co">This is a chuck of documentation</span></a>
<a class="sourceLine" id="cb1-36" title="36"><span class="co">not attached to any particular Haskell</span></a>
<a class="sourceLine" id="cb1-37" title="37"><span class="co">declaration with an untested code block:</span></a>
<a class="sourceLine" id="cb1-38" title="38"></a>
<a class="sourceLine" id="cb1-39" title="39"><span class="co">&gt; answer = 42</span></a>
<a class="sourceLine" id="cb1-40" title="40"></a>
<a class="sourceLine" id="cb1-41" title="41"><span class="co">-}</span></a></code></pre></div>
<p>To prevent obsolescence of your tutorial, use <code>doctest</code>.</p>
<p>That way when youll do a <code>stack test</code> or <code>cabal test</code> youll get errors if some example doesnt work anymore.</p>
<h3 id="examples-doctest">Examples (doctest)</h3>
<p><code>doctest</code> is a great way to provide examples in your code documentation. These example will then be used as tests. Apparently it comes from Python community.</p>
<p>To use <code>doctest</code>, this is very simple:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb2-1" title="1"><span class="co">-- | My function description</span></a>
<a class="sourceLine" id="cb2-2" title="2"><span class="co">-- </span></a>
<a class="sourceLine" id="cb2-3" title="3"><span class="co">-- &gt;&gt;&gt; myFunction 3 4</span></a>
<a class="sourceLine" id="cb2-4" title="4"><span class="co">-- 7</span></a>
<a class="sourceLine" id="cb2-5" title="5"><span class="ot">myFunction ::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">Int</span></a>
<a class="sourceLine" id="cb2-6" title="6">myFunction <span class="ot">=</span> (<span class="op">+</span>)</a></code></pre></div>
<p>And to make it works simply verify you have a <code>test</code> bloc in your <code>.cabal</code> file looking like this:</p>
<pre><code>test-suite doctest
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: DocTest.hs
build-depend: base &gt;= 4.7 &amp;&amp; &lt; 5
, &lt;YOUR_LIBRARY&gt;
, Glob &gt;= 0.7
, doctest &gt;= 0.9.12</code></pre>
<p>and in <code>test/DocTest.hs</code> simply use</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb4-1" title="1"><span class="kw">module</span> <span class="dt">Main</span> <span class="kw">where</span></a>
<a class="sourceLine" id="cb4-2" title="2"></a>
<a class="sourceLine" id="cb4-3" title="3"><span class="kw">import</span> <span class="dt">DocTest</span></a>
<a class="sourceLine" id="cb4-4" title="4"><span class="kw">import</span> <span class="dt">System.FilePath.Glob</span> (glob)</a>
<a class="sourceLine" id="cb4-5" title="5"></a>
<a class="sourceLine" id="cb4-6" title="6">main <span class="ot">=</span> glob <span class="st">&quot;src/**/*.hs&quot;</span> <span class="op">&gt;&gt;=</span> docTest</a></code></pre></div>
<p>Now <code>stack test</code> or <code>cabal test</code> will check the validity of your documentation.</p>
<h2 id="bonuses">Bonuses</h2>
<h3 id="verifying-documentation-coverage">Verifying documentation coverage</h3>
<ol type="1">
<li>Install haddock <code>stack install haddock</code> or <code>cabal install haddock</code></li>
<li>Launch haddock without output format:</li>
</ol>
<pre><code>&gt; haddock src/**/*.hs
Haddock coverage:
100% ( 15 / 15) in 'Data.Duration'
100% ( 3 / 3) in 'Data.Duration.Tutorial'</code></pre>
<h3 id="continuous-integration">Continuous Integration</h3>
<p>There are plenty of alternative solution. I provide the one I believe would be used by most people. So if you use <code>github</code> simply create an account on <a href="http://travis-ci.org"><code>travis</code></a>.</p>
<p>Add a <code>.travis.yml</code> file in your repo containing the content of the file <a href="http://docs.haskellstack.org/en/stable/GUIDE/#travis-with-caching">here</a> and remove the builds you dont need. It will build your project using a lot of different GHC versions and environemnts.</p>
<p>If you are afraid by such its complexity you might just want to use this one:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode .yaml"><code class="sourceCode yaml"><a class="sourceLine" id="cb6-1" title="1"><span class="fu">sudo:</span><span class="at"> </span><span class="ch">false</span></a>
<a class="sourceLine" id="cb6-2" title="2"></a>
<a class="sourceLine" id="cb6-3" title="3"><span class="fu">addons:</span></a>
<a class="sourceLine" id="cb6-4" title="4"> <span class="fu">apt:</span></a>
<a class="sourceLine" id="cb6-5" title="5"> <span class="fu">packages:</span></a>
<a class="sourceLine" id="cb6-6" title="6"> <span class="kw">-</span> libgmp-dev</a>
<a class="sourceLine" id="cb6-7" title="7"></a>
<a class="sourceLine" id="cb6-8" title="8"><span class="co"># Caching so the next build will be fast too.</span></a>
<a class="sourceLine" id="cb6-9" title="9"><span class="fu">cache:</span></a>
<a class="sourceLine" id="cb6-10" title="10"> <span class="fu">directories:</span></a>
<a class="sourceLine" id="cb6-11" title="11"> <span class="kw">-</span> $HOME/.stack</a>
<a class="sourceLine" id="cb6-12" title="12"></a>
<a class="sourceLine" id="cb6-13" title="13"><span class="fu">before_install:</span></a>
<a class="sourceLine" id="cb6-14" title="14"><span class="co"># Download and unpack the stack executable</span></a>
<a class="sourceLine" id="cb6-15" title="15"><span class="kw">-</span> mkdir -p ~/.local/bin</a>
<a class="sourceLine" id="cb6-16" title="16"><span class="kw">-</span> export PATH=$HOME/.local/bin:$PATH</a>
<a class="sourceLine" id="cb6-17" title="17"><span class="kw">-</span> travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin <span class="st">'*/stack'</span></a>
<a class="sourceLine" id="cb6-18" title="18"></a>
<a class="sourceLine" id="cb6-19" title="19"><span class="fu">script:</span></a>
<a class="sourceLine" id="cb6-20" title="20"> <span class="kw">-</span> stack setup &amp;&amp; stack --no-terminal --skip-ghc-check test</a></code></pre></div>
<p>Dont forget to activate your repo in travis.</p>
<p>For some bonus points add the build status badge in your <code>README.md</code> file:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode .markdown"><code class="sourceCode markdown"><a class="sourceLine" id="cb7-1" title="1"><span class="ot">[![Build Status](https://travis-ci.org/user-name/project-name.svg?branch=master)</span>](https://travis-ci.org/user-name/project-name)</a></code></pre></div>
<p>Congratulation! Now if you break your documentation examples, youll get notified.</p>
<h3 id="badges">Badges</h3>
<p>You could add badges to your <code>README.md</code> file.</p>
<p>Here is a list of some: <a href="http://shields.io"><code>shields.io</code></a></p>
<h4 id="hackage">Hackage</h4>
<div class="sourceCode" id="cb8"><pre class="sourceCode .markdown"><code class="sourceCode markdown"><a class="sourceLine" id="cb8-1" title="1"><span class="ot">[![Hackage](https://img.shields.io/hackage/v/packagename)</span>](https://hackage.haskell.org/package/packagename)</a></code></pre></div>
<h4 id="stackage">Stackage</h4>
<p>If you didnt declared your package to <code>stackage</code>, please do it. It isnt much work. Just edit a file to add your package. And youll could be able to add another badge:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode .markdown"><code class="sourceCode markdown"><a class="sourceLine" id="cb9-1" title="1"><span class="ot">[![packagename on Stackage LTS](http://stackage.org/package/packagename/badge/lts-3)</span>](http://stackage.org/lts/package/packagename)</a></code></pre></div>
<p>See <a href="https://www.fpcomplete.com/blog/2015/10/stackage-badges">Stackage Badges</a> for more informations.</p>
<h3 id="creating-a-new-project-with-stack">Creating a new project with <code>stack</code></h3>
<p>If you use <code>stack</code> I suggest you to use the <code>tasty-travis</code> template. It will include the boilerplate for:</p>
<ul>
<li>tests</li>
<li>doctest</li>
<li>benchmark</li>
<li>travis CI</li>
<li>a README file to help you start</li>
</ul>
<p>So edit your <code>~/.stack/config.yaml</code> like this:</p>
<pre><code>templates:
params:
author-name: Your Name
author-email: your@mail.com
copyright: 'Copyright: (c) 2016 Your Name'
github-username: yourusername
category: Development</code></pre>
<p>And then you can create a new projec with:</p>
<pre><code>stack new my-project tasty-travis</code></pre>
<h2 id="generated-documentation">Generated Documentation</h2>
<p>Even not doing anything, if you submit your library to hackage, haddock should generate some API documentation for free.</p>
<p>But to make <em>real</em> documentation you <em>need</em> to add some manual annotations.</p>
<p><strong>Functions</strong>:</p>
<pre><code><span class="highlight">-- | My function description</span>
myFunction :: T1 <span class="highlight">-- ^ arg1 description</span>
-&gt; T2 <span class="highlight">-- ^ arg2 description</span>
myFunction arg1 arg2 = ...</code></pre>
<p><strong>Data</strong>:</p>
<pre><code>data MyData a b
= C1 a b -- ^ doc for constructor C1
| C2 a b -- ^ doc for constructor C2
data MyData a b
= C { a :: TypeA <span class="highlight">-- ^ field a description</span>
, b :: TypeB <span class="highlight">-- ^ field b description</span>
}</code></pre>
<p><strong>Module</strong>:</p>
<pre><code>{-|
Module : MyModule
Description: Short description
Copyright : (c)
License : MIT
Here is a longer description of this module.
With some code symbol @MyType@.
And also a block of code:
@
data MyData = C Int Int
myFunction :: MyData -&gt; Int
@
-}</code></pre>
<p><strong>Documentation Structure</strong>:</p>
<pre><code>module MyModule (
-- * Classes
C(..),
-- * Types
-- ** A data type
T,
-- ** A record
R,
-- * Some functions
f, g
) where</code></pre>
<p>That will generate headings.</p>
<h2 id="other-random-ideas">Other Random Ideas</h2>
<p>In Haskell we have great tools like <a href="http://hayoo.fh-wedel.de"><code>hayoo!</code></a> and <a href="https://www.haskell.org/hoogle/"><code>hoogle</code></a>.</p>
<p>And <code>hackage</code> and <code>stackage</code> provide also a lot of informations.</p>
<p>But generally we lack a lot of Tutorials and Guides. This post was an attempt to help people making more of them.</p>
<p>But there are other good ideas to help improve the situation.</p>
<h3 id="create-a-doc-with-link-to-best-practices">Create a doc with link to best practices</h3>
<p>In clojure when you create a new project using <code>lein new my-project</code> a directory <code>doc</code> is created for you. It contains a file with a link to this blog post:</p>
<ul>
<li><a href="https://jacobian.org/writing/what-to-write/">What to write</a></li>
</ul>
<h3 id="having-a-page-by-functionsymbol-with-comments">Having a page by function/symbol with comments</h3>
<p>If you try to search for some clojure function on a search engine there is a big chance the first result will link to:</p>
<ul>
<li><a href="http://clojuredocs.org"><code>clojuredocs.org</code></a>: try to search for <code>reduce</code>, <code>update-in</code> or <code>index</code> for example</li>
</ul>
<p>For each symbol necessiting a documentation. You dont only have the details and standard documentation. Youll also get:</p>
<ul>
<li>Responsive Design (sometime you want to look at documentation on a mobile)</li>
<li>Contributed Examples</li>
<li>Contributed See Also section</li>
<li>Contributed notes/comments</li>
</ul>
<p><a href="http://clojuredocs.org"><code>clojuredocs.org</code></a> is an independant website from the official Clojure website.</p>
<p>Most of the time, if you google the function you search you end up on <a href="http://clojuredocs.org">clojuredocs</a> for wich there are many contributions.</p>
<p>Currently stackage is closer to these feature than hackage. Because on stackage you have access to the README and also some comments by package.</p>
<p>I believe it would be more efficient to have at least a page by module and why not a page by <em>symbol</em> (data, functions, typeclasses…).</p>
<p>For example, we could provide details about <code>foldl</code> for example. Also as there would be less information to display, it will make the design cleaner.</p>
<p>Today, if you want to help documenting, you need to make a PR to the source of some library. While if we had an equivalent to clojuredocs for Haskell, adding documentation would simply be a few clicks away:</p>
<ol type="1">
<li>login</li>
<li>add/edit some example, comments, see-also section</li>
</ol>
<p>There are more than 23k people on <code>/r/haskell</code>. If only 1% of them would take 10 minutes adding a bit of documentation it will certainly change a lot of things in the percieved documentation quality.</p>
<p>And last but not least,</p>
<h2 id="design-is-important"><strong>Design is important</strong></h2>
<div>
<img src="../../../../Scratch/img/blog/Haskell-Tutorials--a-tutorial/design_is_important.jpg" alt="Design is Important" />
</div>
<p>Design is a vague word. A good design should care not only about how something look, but also how users will interact with it. For example by removing things to focus on the essential.</p>
<p>When I stumble upon some random blog post or random specification in the Haskell community, I had too much a feeling of old fashioned design.</p>
<p>If you look at node.js community lot of their web page look cleaner, easier to read and in the end, more user friendly.</p>
<p>Haskell is very different from node, I wouldnt like to replace all long and precise documentation with short human unprecise concepts. I dont want to transform scientific papers by tweets.</p>
<p>But like the scientific community has upgraded with the use of LaTeX, I believe we could find something similar that would make, very clean environment for most of us. A kind of look and feel that will be</p>
<ul>
<li>modern</li>
<li>device friendly (either on computer, mobile, tablet)</li>
<li>efficient, focus on what is most important and is helpful</li>
</ul>
</div>
<div id="afterarticle">
<div id="social">
<a href="/rss.xml" target="_blank" rel="noopener noreferrer nofollow" class="social">RSS</a>
·
<a href="https://twitter.com/home?status=http%3A%2F%2Fyannesposito.com/Scratch/en/blog/Haskell-Tutorials--a-tutorial/%20via%20@yogsototh" target="_blank" rel="noopener noreferrer nofollow" class="social">Tweet</a>
·
<a href="http://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fyannesposito.com/Scratch/en/blog/Haskell-Tutorials--a-tutorial/" target="_blank" rel="noopener noreferrer nofollow" class="social">FB</a>
<br />
<a class="message" href="../../../../Scratch/en/blog/Social-link-the-right-way/">These social sharing links preserve your privacy</a>
</div>
<div id="navigation">
<a href="../../../../">Home</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/en/blog">Blog</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/en/softwares">Softwares</a>
<span class="sep">¦</span>
<a href="../../../../Scratch/en/about">About</a>
</div>
<div id="totop"><a href="#header">↑ Top ↑</a></div>
<div id="bottom">
<div>
Published on 2016-05-06
</div>
<div>
<a href="https://twitter.com/yogsototh">Follow @yogsototh</a>
</div>
<div>
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_US">Yann Esposito©</a>
</div>
<div>
Done with
<a href="http://www.vim.org" target="_blank" rel="noopener noreferrer nofollow"><strike>Vim</strike></a>
<a href="http://spacemacs.org" target="_blank" rel="noopener noreferrer nofollow">spacemacs</a>
<span class="pala">&amp;</span>
<a href="http://nanoc.ws" target="_blank" rel="noopener noreferrer nofollow"><strike>nanoc</strike></a>
<a href="http://jaspervdj.be/hakyll" target="_blank" rel="noopener noreferrer nofollow">Hakyll</a>
</div>
<hr />
<div style="max-width: 100%">
<a href="https://cardanohub.org">
<img src="../../../../Scratch/img/ada-logo.png" class="simple" style="height: 16px;
border-radius: 50%;
vertical-align:middle;
display:inline-block;" />
ADA:
</a>
<code style="display:inline-block;
word-wrap:break-word;
text-align: left;
vertical-align: top;
max-width: 85%;">
DdzFFzCqrhtAvdkmATx5Fm8NPJViDy85ZBw13p4XcNzVzvQg8e3vWLXq23JQWFxPEXK6Kvhaxxe7oJt4VMYHxpA2vtCFiP8fziohN6Yp
</code>
</div>
</div>
</div>
</div>
</div>
</body>
</html>