Skip to content

Instantly share code, notes, and snippets.

@neongreen
Created February 3, 2018 20:57
Show Gist options
  • Save neongreen/e6eee632b769174a276c25b95c245ebe to your computer and use it in GitHub Desktop.
Save neongreen/e6eee632b769174a276c25b95c245ebe to your computer and use it in GitHub Desktop.
<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Dirt Cheap Haskell: Library</title><id>https://dirtcheaphaskell.io#library</id><updated>2017-11-02T00:00:00Z</updated><link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="https://dirtcheaphaskell.io#library"/><entry><id>2017-11-02-editor-integration</id><title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Haskell integration with editors</title><updated>2017-11-02T00:00:00Z</updated><content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">&lt;details class="qa-session"&gt;&lt;summary&gt;&lt;span class="qa-header"&gt;&lt;span id="2017-11-02-editor-integration" class="qa-title"&gt;&lt;a href="#2017-11-02-editor-integration"&gt;Haskell integration with editors&lt;/a&gt;&lt;/span&gt;&lt;time class="qa-time"&gt;2017-11-02&lt;/time&gt;&lt;/span&gt;&lt;/summary&gt;&lt;div class="qa-message qa-role-client qa-msg-highlight"&gt;&lt;p class="qa-author"&gt;&lt;span class="qa-username"&gt;Client&lt;/span&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;Do any non-Vim/Emacs editors have good Haskell integration?&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-consultant qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;a href="https://github.com/int-index"&gt;&lt;img src="https://avatars1.githubusercontent.com/u/4061728?v=4&amp;amp;s=128" class="qa-userpic"&gt;&lt;span class="qa-username"&gt;Vladislav Zavialov&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;I would go as far as to say that there&amp;#39;s no good editor integration
for Haskell at all. There&amp;#39;s &lt;code&gt;ghc-mod&lt;/code&gt; and the ecosystem around it, but
it stops being usable as soon as the project is big enough. It&amp;#39;s just
too slow. And lots of Haskell tooling suffers from the issue that
there&amp;#39;s no good package with the Haskell AST (there&amp;#39;s
&lt;code&gt;haskell-src-exts&lt;/code&gt;, but it&amp;#39;s just not what the compiler uses, and the
discrepancies are often noticable). Another story is integration with
build systems... Honestly, at one point I gave up and decided not to
use Haskell tooling, it&amp;#39;s broken.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/alanz"&gt;@alanz&lt;/a&gt; is doing an immense amount of work to fix that.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-consultant qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;a href="https://github.com/neongreen"&gt;&lt;img src="https://avatars2.githubusercontent.com/u/1523306?v=4&amp;amp;s=128" class="qa-userpic"&gt;&lt;span class="qa-username"&gt;Artyom Kazak&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;NB: I heard from a coworker that Sublime can be set up to work as well
as Emacs; if you consider Emacs&amp;#39;s integration good, I could ask
him for details about his Sublime setup if you&amp;#39;re interested.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-consultant qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;a href="https://github.com/int-index"&gt;&lt;img src="https://avatars1.githubusercontent.com/u/4061728?v=4&amp;amp;s=128" class="qa-userpic"&gt;&lt;span class="qa-username"&gt;Vladislav Zavialov&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;There were discussions in the GHC mailing list about defining an
external AST for GHC which could be used by various tooling. They also
plan to apply the principles from the &lt;a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/11/trees-that-grow.pdf"&gt;“Trees That Grow” paper&lt;/a&gt;,
which is an amazing idea. All of it is happening right now, and
Haskell will get the tooling it deserves sooner or later (but, sadly,
&amp;quot;later&amp;quot; sounds more realistic).&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;#39;d still recommend &lt;a href="https://hackage.haskell.org/package/hasktags"&gt;&lt;code&gt;hasktags&lt;/code&gt;&lt;/a&gt; to generate tags.
Although it doesn&amp;#39;t work very good either (sometimes it misses some
definitions, sometimes it indexes non-definitions), but it works 90%
of the time and &amp;quot;Jump to definition&amp;quot; is just something that gives an
immense productivity boost (even if a bit broken).&lt;/p&gt;
&lt;p&gt;One important caveat is that you can&amp;#39;t jump to definitions generated
by Template Haskell. That&amp;#39;s quite obvious in retrospect, because
&lt;code&gt;hasktags&lt;/code&gt; doesn&amp;#39;t run the compile-time code, but might be a bit
disappointing when you can&amp;#39;t jump to a lens generated by &lt;code&gt;makeLenses&lt;/code&gt;
or something like that.&lt;/p&gt;
&lt;p&gt;And if you use Stack as your build tool, just having &lt;code&gt;stack build --file-watch&lt;/code&gt; in a terminal window next to the editor is often
sufficient.&lt;/p&gt;
&lt;p&gt;Most of the people who worked on tooling such as &lt;code&gt;haskell-mode&lt;/code&gt;,
&lt;code&gt;ghc-mod&lt;/code&gt;, and &lt;code&gt;ide-backend&lt;/code&gt;, decided to consolidate their efforts and
work on &lt;a href="https://github.com/haskell/haskell-ide-engine"&gt;&lt;code&gt;haskell-ide-engine&lt;/code&gt;&lt;/a&gt;. What&amp;#39;s exciting about this is that
they plan to support &lt;a href="https://microsoft.github.io/language-server-protocol"&gt;Language Server Protocol&lt;/a&gt;. Basically, this
means that we&amp;#39;ll get Haskell support in all editors that support LSP,
so it&amp;#39;s going to be N+M rather than N×M.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-client qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;span class="qa-username"&gt;Client&lt;/span&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;Ok cool, I’ll try out &lt;code&gt;hasktags&lt;/code&gt; tomorrow. I’ll also try
&lt;code&gt;haskell-ide-engine&lt;/code&gt; with VS Code tomorrow, looks like that’s working?&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-consultant qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;a href="https://github.com/int-index"&gt;&lt;img src="https://avatars1.githubusercontent.com/u/4061728?v=4&amp;amp;s=128" class="qa-userpic"&gt;&lt;span class="qa-username"&gt;Vladislav Zavialov&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;Things are working up until they break, which might be when (1) the
project is too big and the tooling gets painfully slow to use, (2) you
need an obscure language extension that wreaks havoc on the tooling.&lt;/p&gt;
&lt;p&gt;Especially if it&amp;#39;s an extension implemented in the latest compiler
version and it&amp;#39;s a syntactic addition. When &lt;code&gt;-XLambdaCase&lt;/code&gt; was
introduced, everything &lt;code&gt;haskell-src-exts&lt;/code&gt;-based just stopped working –
that&amp;#39;s just one example.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/details&gt;</content><link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="https://dirtcheaphaskell.io#2017-11-02-editor-integration"/></entry><entry><id>2017-11-02-monad-transformers</id><title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Monad transformers</title><updated>2017-11-02T00:00:00Z</updated><content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">&lt;details class="qa-session"&gt;&lt;summary&gt;&lt;span class="qa-header"&gt;&lt;span id="2017-11-02-monad-transformers" class="qa-title"&gt;&lt;a href="#2017-11-02-monad-transformers"&gt;Monad transformers&lt;/a&gt;&lt;/span&gt;&lt;time class="qa-time"&gt;2017-11-02&lt;/time&gt;&lt;/span&gt;&lt;/summary&gt;&lt;div class="qa-message qa-role-client qa-msg-highlight"&gt;&lt;p class="qa-author"&gt;&lt;span class="qa-username"&gt;Client&lt;/span&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;I&amp;#39;ve got a kinda generic question. How do monad transformers work?&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-consultant qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;a href="https://github.com/int-index"&gt;&lt;img src="https://avatars1.githubusercontent.com/u/4061728?v=4&amp;amp;s=128" class="qa-userpic"&gt;&lt;span class="qa-username"&gt;Vladislav Zavialov&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;Well, the reason to use monad transformers is to get the &lt;code&gt;Monad&lt;/code&gt;
instances automatically. For example, there&amp;#39;s no runtime difference
between &lt;code&gt;a -&amp;gt; IO b&lt;/code&gt; and &lt;code&gt;ReaderT a IO b&lt;/code&gt;, but the latter has a &lt;code&gt;Monad&lt;/code&gt;
instance, whereas the former doesn&amp;#39;t. Actually, that&amp;#39;s it.&lt;/p&gt;
&lt;p&gt;Of course, we could use a function instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-haskell"&gt;state -&amp;gt; env -&amp;gt; IO (Either exc (a, state))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But we want a &lt;code&gt;(&amp;gt;&amp;gt;=)&lt;/code&gt; that does all the plumbing, and to get this we
express the same thing as a transformers stack:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-haskell"&gt;StateT state (ReaderT env (ExceptT exc IO)) a
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-client qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;span class="qa-username"&gt;Client&lt;/span&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;Ok, that makes sense.&lt;/p&gt;
&lt;p&gt;I’ll read that chapter of @bitemyapp’s book on that and ask you if I
have any specific questions.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-consultant qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;a href="https://github.com/int-index"&gt;&lt;img src="https://avatars1.githubusercontent.com/u/4061728?v=4&amp;amp;s=128" class="qa-userpic"&gt;&lt;span class="qa-username"&gt;Vladislav Zavialov&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;And we couldn&amp;#39;t define a &lt;code&gt;Monad&lt;/code&gt; instance for &lt;code&gt;a -&amp;gt; IO b&lt;/code&gt; because it&amp;#39;s
unclear whether we want it to behave as &lt;code&gt;ReaderT a IO b&lt;/code&gt; or &lt;code&gt;Reader a (IO b)&lt;/code&gt;. So the structure of transformers layers tells the compiler
how deep we want &lt;code&gt;(&amp;gt;&amp;gt;=)&lt;/code&gt; to inspect the structure of the types.&lt;/p&gt;
&lt;p&gt;(Well, actually, &lt;code&gt;a -&amp;gt; IO b&lt;/code&gt; has a &lt;code&gt;Monad&lt;/code&gt; instance and it&amp;#39;s indeed
equivalent to &lt;code&gt;Reader a (IO b)&lt;/code&gt; rather than &lt;code&gt;ReaderT a IO b&lt;/code&gt;.)&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/details&gt;</content><link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="https://dirtcheaphaskell.io#2017-11-02-monad-transformers"/></entry><entry><id>2017-11-02-servant-yesod</id><title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Servant vs Yesod</title><updated>2017-11-02T00:00:00Z</updated><content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">&lt;details class="qa-session"&gt;&lt;summary&gt;&lt;span class="qa-header"&gt;&lt;span id="2017-11-02-servant-yesod" class="qa-title"&gt;&lt;a href="#2017-11-02-servant-yesod"&gt;Servant vs Yesod&lt;/a&gt;&lt;/span&gt;&lt;time class="qa-time"&gt;2017-11-02&lt;/time&gt;&lt;/span&gt;&lt;/summary&gt;&lt;div class="qa-message qa-role-client qa-msg-highlight"&gt;&lt;p class="qa-author"&gt;&lt;span class="qa-username"&gt;Client&lt;/span&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;How does Servant compare to Yesod?&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-consultant qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;a href="https://github.com/int-index"&gt;&lt;img src="https://avatars1.githubusercontent.com/u/4061728?v=4&amp;amp;s=128" class="qa-userpic"&gt;&lt;span class="qa-username"&gt;Vladislav Zavialov&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;The primary philosophical difference is that Servant tries to do
everything using type-level tricks, while Yesod uses Template Haskell
a lot. The code looks very different with these frameworks because of
that. What&amp;#39;s common between them is that they&amp;#39;re both &lt;code&gt;wai&lt;/code&gt;-based,
meaning they can run atop any &lt;code&gt;wai&lt;/code&gt;-compatible server (&lt;code&gt;warp&lt;/code&gt; or
&lt;code&gt;warp-tls&lt;/code&gt;), and that&amp;#39;s great. I recommend against frameworks that
aren&amp;#39;t &lt;code&gt;wai&lt;/code&gt;-based (this includes Snap and Happstack) because &lt;code&gt;warp&lt;/code&gt;
is a great web server, it&amp;#39;s performant and configurable. Now, I&amp;#39;m not
going to give a point-by-point comparison for Servant and Yesod
because they&amp;#39;re just so different that having such a list might be
misleading. For instance, they both support type-safe routing, but
it&amp;#39;s done in wildly different ways.&lt;/p&gt;
&lt;p&gt;I&amp;#39;d say it&amp;#39;s useful to know both. If you implement a web API that
talks to the front-end using JSON, I recommend Servant. If you want a
multi-page web-app that has user authorization and stuff like this,
Yesod is the path of least resistance. And since both of them are
&lt;code&gt;wai&lt;/code&gt;-based (did I mention it&amp;#39;s great? well, here&amp;#39;s another reason
why) you can embed a Servant website as a subsite for Yesod, and vice
versa, you can run a Yesod website as part of a Servant API.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-client qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;span class="qa-username"&gt;Client&lt;/span&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;I have more experience with Yesod (am a contributor, read a lot of the
code) but I’m finding that I’m just ripping out most of it – so I’ll
give Servant a try.&lt;/p&gt;
&lt;p&gt;I’m a little worried it looks too complex to introduce to beginners.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class="qa-message qa-role-consultant qa-msg-casual"&gt;&lt;p class="qa-author"&gt;&lt;a href="https://github.com/int-index"&gt;&lt;img src="https://avatars1.githubusercontent.com/u/4061728?v=4&amp;amp;s=128" class="qa-userpic"&gt;&lt;span class="qa-username"&gt;Vladislav Zavialov&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="qa-content"&gt;&lt;p&gt;It definitely is very complex on the inside, if you try to look at the
definitions they&amp;#39;re monstrous – but I&amp;#39;d claim that using it isn&amp;#39;t hard
at all. Those definitions are so complex precisely to allow for
elegant code that uses them, they try to hide a lot of complexity.&lt;/p&gt;
&lt;p&gt;Of course, it doesn&amp;#39;t help that Haskell doesn&amp;#39;t have good facilities
for type-level programming. In a language where functions are promoted
and there&amp;#39;s proper relevant quantification (might be getting a bit
technical here), Servant could be implemented much nicer.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/details&gt;</content><link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="https://dirtcheaphaskell.io#2017-11-02-servant-yesod"/></entry></feed>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment