Skip to content

Instantly share code, notes, and snippets.

@erantapaa
Last active August 6, 2017 01:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erantapaa/e7062927168a7dbc8fce5e427822ddbb to your computer and use it in GitHub Desktop.
Save erantapaa/e7062927168a7dbc8fce5e427822ddbb to your computer and use it in GitHub Desktop.
Bootstrapping a Haskell environment using Stack
  1. Download stack
  2. Decide on an resolver, e.g. lts-8.24
  3. Set the resolver in ~/.stack/global-project/stack.yaml
  4. In a work directory:
  • Run: stack get cabal
  • Add a stack.yaml file to the pull sources
  • Run: stack install. The cabal executable should be installed in ~/.local/bin.
  1. Grab the cabal.config for the resolver: curl https://www.stackage.org/lts-8.24/cabal.config
  2. Use the build-everything-cabal script below to generate a everything.cabal file with all the packages listed in the build-depends: field. Place the cabal file in ~/.stack/global-project. Now you can use stack install <package> outside a project directory and get packages installed.

Some things to install:

  • stack install ghc-mod
  • stack install hlint
#!/usr/bin/env python
#
# build a everything.cabal file for a particular resolver
import requests
import re
def get_cabal_config(resolver):
url = "https://www.stackage.org/" + resolver + "/cabal.config"
r = requests.get(url)
return r.text
def get_resolver_packages(resolver):
config = get_cabal_config(resolver)
return re.findall("^\s*(?:constraints:\s*)?(\w[\w-]*)\s+==", config, re.M)
def gen_cabal_config(packages, description):
config = """
name: everything
description: {}
version: 0.0.1
build-type: Simple
cabal-version: >= 1.10
library
build-depends:
base >= 4.7 && < 5
""".format(description) + "\n".join( [ " , " + p for p in packages ] )
return config
resolver = "lts-8.24"
packages = get_resolver_packages(resolver)
count = len(packages)
description = "packages in {} - count = {}".format(resolver, count)
print gen_cabal_config(packages, description)

Some notes on Haskell-related vim plugins

Syntastic plugins:

  • ghc_mod
  • hlint

Syntastic plugins have attributes of being available and enabled. Use the :SyntasticInfo command to determine which plugins were detected as available and then which one was selected as enabled.

Use the variable g:syntastic_haskell_checkers to select which one you want to use, e.g.:

let g:syntastic_haskell_checkers = ['ghc_mod']
Syntastic plugin ghc_mod

This plugin does not work. The _IsAvailable function tries to validate the version of ghc-mod, but I doubt that check is necessary anymore. Also, the GetLocLines function adds a --boundary option which is not recognized by recent versions of ghc-mod.

If you remove the _IsAvailable function and fix GetLocLines so that the command line used is:

    let makeprg = self.makeprgBuild({
         \ 'exe': self.getExecEscaped() . ' check' })

this checker will work. Note that it is not normally enabled by default, so use the ..._checkers variable to select it.

Another useful variable setting to use with this checker is:

let g:syntastic_quiet_messages = { "level" : "warnings" }

to suppress warnings.

Syntastic plugin hlint

This one seems to work, and for some strange reason, it is automatically enabled even if the ghc_mod checker is available.

Also see :help syntastic-aggregating-errors for info on aggregating errors from multiple checkers.

Requires a working hlint command which is provided by the hlint package on Hackage.

ghc-mod

The ghc-mod plugin (not to be confused with the Syntastic ghc_mod checker) provides the ability to inquire the types of expressions in the source.

Here are some example key bindings to use with this plugin:

map <silent> tw :GhcModTypeInsert<CR>
map <silent> ts :GhcModSplitFunCase<CR>
map <silent> tq :GhcModType<CR>
map <silent> te :GhcModTypeClear<CR>

This plugin will work if you have a working ghc-mod command.

neco-ghc

neco-ghc provides autocompletion of module, type and function names via vim's omnicompletion feature. This plugin requires a working ghc-mod command.

Use C-X C-O to bring up a list of possible completions at the current cursor position.

Enable neco-ghc in Haskell mode with:

let g:haskellmode_completion_ghc = 1
autocmd FileType haskell setlocal omnifunc=necoghc#omnifunc

in your .vimrc file.

Setting up the ghc-mod command

All of these plugins (except for the hlint checker) require a working ghc-mod command.

I am using stack exec ghc-mod as my ghc-mod command by setting up a wrapper script in my personal ~/bin directory which looks like:

#!/bin/sh    
stack exec ghc-mod -- "$@"

If executed outside a stack project directory, stack will look in the "global" project directory ~/.stack/global-project for the stack.yaml and .cabal files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment