diff --git a/playbooks/roles/fedora_packages/tasks/haskell.yml b/playbooks/roles/fedora_packages/tasks/haskell.yml new file mode 100644 index 0000000..eda31a6 --- /dev/null +++ b/playbooks/roles/fedora_packages/tasks/haskell.yml @@ -0,0 +1,7 @@ +--- +- name: Install ghc and hlint + dnf: + name: + - "@ghc:8.10" + - hlint + state: present diff --git a/playbooks/roles/haskell/tasks/main.yml b/playbooks/roles/haskell/tasks/main.yml new file mode 100644 index 0000000..752e25d --- /dev/null +++ b/playbooks/roles/haskell/tasks/main.yml @@ -0,0 +1,13 @@ +--- +- name: Create directories for configuration + shell: mkdir ~/.ghc + +- name: Install ghci.conf + template: + src: templates/ghci.conf.j2 + dest: ~/.ghc/ghci.conf + +- name: Install HLint.hs + template: + src: templates/HLint.hs.j2 + dest: ~/.ghc/HLint.hs \ No newline at end of file diff --git a/playbooks/roles/haskell/templates/HLint.hs.j2 b/playbooks/roles/haskell/templates/HLint.hs.j2 new file mode 100644 index 0000000..3674e29 --- /dev/null +++ b/playbooks/roles/haskell/templates/HLint.hs.j2 @@ -0,0 +1,60 @@ +import "hint" HLint.Builtin.All +import "hint" HLint.Default +import "hint" HLint.Dollar + +import Data.Map +import Control.Arrow +import Control.Monad +import Control.Monad.State + +warn = (\ x -> f $ g x) ==> f . g + +-- List +warn = cycle [c] ==> repeat c + +warn = x == [] ==> null x where note = "generalize" +warn = [] == x ==> null x where note = "generalize" + +warn = x /= [] ==> not (null x) where note = "generalize" +warn = [] /= x ==> not (null x) where note = "generalize" + +warn = fst (unzip x) ==> map fst x +warn = snd (unzip x) ==> map snd x + +warn "Use not . null" = length x > 0 ==> not (null x) where note = "increases laziness" +warn "Use not . null" = length x >= 1 ==> not (null x) where note = "increases laziness" + +-- Map +warn = map fst (Data.Map.toList x) ==> Data.Map.keys x +warn = map snd (Data.Map.toList x) ==> Data.Map.elems x + +warn = foldr f v (Data.Map.elems x) ==> Data.Map.foldr f v x +warn = Data.Maybe.fromMaybe d (Data.Map.lookup k m) ==> Data.Map.findWithDefault d k m + +-- Arrows + +warn = id *** id ==> id +warn = Control.Arrow.first id ==> id +warn = Control.Arrow.second id ==> id + +warn = Control.Arrow.first f (Control.Arrow.second g x) ==> (f Control.Arrow.*** g) x +warn = Control.Arrow.second f (Control.Arrow.first g x) ==> (g Control.Arrow.*** f) x + +warn = Control.Arrow.first f (Control.Arrow.first g x) ==> Control.Arrow.first (f . g) x +warn = Control.Arrow.second f (Control.Arrow.second g x) ==> Control.Arrow.second (f . g) x + +warn = (a *** b) ((c &&& d) x) ==> ((a . c) Control.Arrow.&&& (b . d)) x +warn = (a *** b) ((c *** d) x) ==> ((a . c) Control.Arrow.*** (b . d)) x + +warn = Control.Arrow.first f ((a *** b) x) ==> ((f . a) Control.Arrow.*** b) x +warn = Control.Arrow.second f ((a *** b) x) ==> (a Control.Arrow.*** (f . b)) x +warn = (a *** b) (Control.Arrow.first f x) ==> ((a . f) Control.Arrow.*** b) x +warn = (a *** b) (Control.Arrow.second f x) ==> (a Control.Arrow.*** (b . f)) x + +warn = Control.Arrow.first f ((a &&& b) x) ==> ((f . a) Control.Arrow.&&& b) x +warn = Control.Arrow.second f ((a &&& b) x) ==> (a Control.Arrow.&&& (f . b)) x + +-- State + +warn = fmap f Control.Monad.State.get ==> Control.Monad.State.gets f +warn = Control.Monad.liftM f Control.Monad.State.get ==> Control.Monad.State.gets f diff --git a/playbooks/roles/haskell/templates/ghci.conf.j2 b/playbooks/roles/haskell/templates/ghci.conf.j2 new file mode 100644 index 0000000..840d088 --- /dev/null +++ b/playbooks/roles/haskell/templates/ghci.conf.j2 @@ -0,0 +1,72 @@ +-- GHCi customization file + +-- vim: syntax=haskell expandtab + +-- some sections are comented out with comments starting with -- &, +-- so you can uncomment them by removing this prefix to enamble them +-- note: block comments do not work here, the same holds for layout rule + + +-- Save to ~/.ghc/ghci.conf +-- Most of the code was taken from the official Haskell wiki. +-- https://wiki.haskell.org/GHC/GHCi + +-- set coloured prompt with loaded modules on separate line +-- +-- :set prompt "\ESC[1;34m%s\n\ESC[0;34m\x03BB> \ESC[m" +-- -bold-blue- -blue---- -lambda -black- + +-- Set all warning on by default +-- but disable type defaults warning +:set -Wall +:set -Wno-type-defaults + +-- The following definitions were taken from "getting more out of ghci", the mini-tutorial +-- + +-- make commands helpful +:{ +let { cmdHelp _ msg "--help" = return $ "putStrLn " ++ show msg + ; cmdHelp cmd _ other = cmd other } +:} + +-- :pwd, :ls +let pwd _ = return "System.Directory.getCurrentDirectory >>= putStrLn" +:def pwd cmdHelp pwd ":pwd\t\t\t-- print working directory" +:{ +let ls p = return $ "mapM_ putStrLn =<< System.Directory.getDirectoryContents "++show path + where {path = if (null p) then "." else p} +:} +:def ls cmdHelp ls ":ls []\t\t-- list directory (\".\" by default)" + +-- :redir +:{ +let redir varcmd = + case break Data.Char.isSpace varcmd of + { (var,_:cmd) -> return $ unlines + [":set -fno-print-bind-result" + ,"tmp <- System.Directory.getTemporaryDirectory" + ,"(f,h) <- System.IO.openTempFile tmp \"ghci\"" + ,"sto <- GHC.IO.Handle.hDuplicate System.IO.stdout" + ,"GHC.IO.Handle.hDuplicateTo h System.IO.stdout" + ,"System.IO.hClose h" + ,cmd + ,"GHC.IO.Handle.hDuplicateTo sto System.IO.stdout" + ,"let readFileNow f = readFile f >>= \\t->length t `seq` return t" + ,var++" <- readFileNow f" + ,"System.Directory.removeFile f"] + ; _ -> return "putStrLn \"usage: :redir \"" } +:} +:def redir cmdHelp redir ":redir \t-- execute , redirecting stdout to " + +-- :hlint +-- requires hlint executable in PATH +-- tries to load ~/.ghc/HLint.hs with additional hints +:{ +:def hlint \extra -> return $ unlines + [":unset +t +s" + ,":set -w" + ,":redir hlintvar1 :show modules" + ,":cmd return $ \":! hlint --color --hint ~/.ghc/HLint.hs \" ++ unwords (map (takeWhile (/=',') . drop 2 . dropWhile (/= '(')) $ lines hlintvar1) ++ \" \" ++ " ++ show extra + ] +:}