If you want to know how we reduced 4000 lines, skip to the architecture part.

I’ve been having a blast working with haskell-mode project. With this blog post I’ll conclude my HSoC 2017.

Summary of my work (Important PRs):

  • Used hideshow.el to rewrite haskell-collapse.el. This allows us to view a lot of code in one page. Added docs too.
    • PR: #1521
    • Status: Merged.
  • Improved build mechanism for Travis-CI and AppVeyor.
    • Travis-CI (Platform: Ubuntu or GNU/Linux)
      • Emacs-24, GHC 8.0.2
      • Emacs-25, GHC 8.0.2
      • Emacs-snapshot, GHC 8.0.2
    • AppVeyor (Platform: Windows)
      • Emacs-24, GHC 8.2.1
      • Emacs-25, GHC 8.2.1
    • PR: #1538
    • Status: Merged.
  • Made with-temp-dir macro platform independent (used to emulate a directory when writing tests), added util function to kill buffer unconditionally (also useful while writing tests).
    • PR: #1539
    • Status: Merged.
  • Added some string utility functions such as trim suffix, trim prefix etc.
    • PR: #1540
    • Status: Merged.
  • Revamped inf-haskell mode. It is a REPL based on Comint. So we get all the standard keybindings such as M-n, M-p, M-r and much more for free. This is very similar to haskell-interactive-mode (REPL) in terms of how it starts the process. It uses haskell-process-type this can be set using a defcustom or it can be inferred. Added tests and Documentation.
    • PR: #1543
    • Status: Merged.
  • Revamped HsCompilation. Automatically infers the compilation command with the presence of stack.yaml, abc.cabal etc. Uses the same mechanism as of haskell-interactive-mode and inf-haskell. It is a breaking change. Removed some defcustoms added new defcustoms.
    • PR: #1545
    • Status: Open (controversial to merge, reasons in the comments of PR)
  • Revamped interactive-haskell-mode. This is an architectural change. Previously we had multiple simultaneous sessions per Emacs process. Since we had multiple sessions, it was a little bit difficult to manage and use many sessions. Now with this PR we have only one session per Emacs process. This is a simplification from the user’s and the programmer’s perspective. The main change is that we are using inf-haskell module to talk with the haskell REPL instead of haskell-interactive-mode module. Also remember that showing completions, types etc is done by querying the haskell REPL process.
    • PR: #1547
    • Status: WIP (Needs Docs as of 2nd Sept 2017)
    • Status: Under review (as of 6th Sept 2017)

It seems like you are not bringing anything new to the table why bother changing from haskell-interactive-mode to inf-haskell?

haskell-interactive-mode has feature duplication with Comint. We can reduce the lines of code by replacing haskell-interactive-mode with inf-haskell that uses Comint. The result is reduction in more than 4000 lines of code with almost all the features.

Tell me more about this architectural change.

First we switched the REPL from haskell-interactive-mode to inf-haskell in one of the previous PRs. If we look at the main module that depends on the haskell-interactive-mode, it is interactive-haskell-mode. interactive-haskell-mode is the minor that provides interactive editing features such as completion-at-point-functions, jump to function definition, loading the file in buffer into the GHCi REPL and other features. With this PR, we will not need haskell-interactive-mode and we can switch to inf-haskell. When I say inf-haskell think that it is written with Comint, so less lines of code. On the other hand with haskell-interactive-mode we are trying to create a Comint alternative and then trying to use it.

interactive-haskell-mode is not the only mode dependent on the inf-haskell. haskell-doc-mode, ghci-script-mode and others which were previously dependent on haskell-interactive-mode will now be switched to inf-haskell.

If we replace haskell-interactive-mode with inf-haskell, a lot of other modules related to haskell-interactive-mode such as haskell-process, haskell-session and more can be killed. As a result we were able to reduce the code base by more than 4000 lines.

OK. We managed to eliminate a big chunk of code by using a library (Comint). What did we loose?

Now we are asking the right questions. Since we had to change the way that we were communicating with the haskell process from haskell-interactive-mode to inf-haskell, we had to change the working of lot of modules. We had to refactor them, occasionally add some tests. Modify some tests to work with the new inf-haskell.

We lost two features namely haskell-debug-mode and trigger-suggestions. The reason is that we did not have enough time and these features did not have enough tests. It was pointed out in the issue #1110, that making trigger suggestion to work reliably would need some work.

Could you not have done this in parts and still retained the features? That is make inf-haskell and haskell-interactive-mode coexist?

If some features depend on inf-haskell and some depend on haskell-interactive-mode we will need two haskell REPL processes for this to work. That is not pretty.

Acknowledgment

I’d like to thank Gracjan Polak for mentoring and guiding me. I’d also like to thank the haskell.org community for giving me an opportunity to participate in this internship. I’d also like to thank #emacs irc channel on Freenode for helping me with my questions. I’d also like to thank the StackOverflow community for answering my questions.

Miscellaneous

I have become an Emacs wizard (some what) in the process of contributing to haskell-mode. My workflow has been altered a lot (for the better). I just casually read the code along with the documentation while writing Elisp these days. While working with other languages, I used to read the docs and write code, but while writing Elisp, if I find the documentation inadequate, I can just read the code. Everything is a C-h f or C-h v away. This workflow is just amazing.

I started using HELM on the way and it has improved my productivity considerably. My mentor suggested that I start using Paredit and Edebug while writing Elisp. I did start using Paredit and it is really good. I’ll be using it whenever I write lisp. On the other hand I did not get around using Edebug. This is because I’ve never used a debugger before and the concept seems to foreign to me, also I’m very lazy when it comes to altering my work pattern.



I was using Emacs 25 in my setup. Tests were failing in CI for Emacs 24, I had to debug and make it work for Emacs 24. It was not a very good experience because I didn’t want to mess up my Emacs installation, so I installed Emacs 24 in a VM. In the mean while I found out I’ve become incapable of using vanilla Emacs (this happened while using Emacs in VM).