Haskell: Difference between revisions

Pigs (talk | contribs)
Crasm (talk | contribs)
Scripting: Swap (legacy?) `haskellPackages.ghcWithPackages` for `ghc.withPackages` and add better starting examples for shell scripting with Haskell, using `Shh` in addition to `Turtle`.
Line 25: Line 25:
=== Scripting ===
=== Scripting ===


For simple scripts, you can directly use nix-shell to get a redistributable Haskell script that you can run on any Nix system with <code>./my-script.hs</code>:
For redistributable Haskell scripts on any Nix system, you can use a nix-shell shebang.
<syntaxhighlight lang=haskell>
<syntaxhighlight lang="haskell">#!/usr/bin/env nix-shell
#!/usr/bin/env nix-shell
#! nix-shell --pure -i runghc -p "ghc.withPackages (pkgs: [ pkgs.turtle ])"
#!nix-shell --pure -i runghc -p "haskellPackages.ghcWithPackages (pkgs: [ pkgs.turtle ])"
{-# LANGUAGE OverloadedStrings #-}
import Turtle


main = do
main = do
   -- do stuff
   -- do stuff
   putStrLn "Hello world from a distributable Haskell script!"
   echo "Hello world from a distributable Haskell script!"</syntaxhighlight>
</syntaxhighlight>
 
To remove the additional latency overhead of a nix-shell, add GHC to <code>environment.systemPackages</code> and call <code>runghc</code> in the shebang.<syntaxhighlight lang="nix">
  environment.systemPackages = with pkgs; [
    ...
    (ghc.withPackages (hsPkgs: with hsPkgs; [
      turtle  # Faster startup time with all external shell commands
      shh      # Piping operators and other goodies
      ...      # ...anything else you want!
    ])
  ];
</syntaxhighlight>Here's a basic example using the Shh module rather than Turtle, so it can use the pipe operator:<syntaxhighlight lang="haskell">
#!/usr/bin/env runghc
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE OverloadedStrings #-}
import Shh
 
-- $(loadEnv SearchPath) -- Loads entire PATH, may be slow
load SearchPath [ "dd", "sha512sum" ]


To write inline Haskell scripts in nix-code, refer to [[Nix-writers#Haskell]].
main = do
  dd "if=/dev/urandom" "bs=4K" "count=1" |> sha512sum
</syntaxhighlight>To write inline Haskell scripts in nix-code, refer to [[Nix-writers#Haskell]].


Read [[#Overrides]] if some packages are broken.
Read [[#Overrides]] if some packages are broken.
Line 43: Line 64:
[https://www.haskell.org/cabal/ Cabal] is the basic Haskell tool used to configure builds and is internally used by all the Haskell's packaging methods (including stack and nix). If one does not care about the reproducibility/caching offered by nix, it is always possible to use cabal like in a normal system:
[https://www.haskell.org/cabal/ Cabal] is the basic Haskell tool used to configure builds and is internally used by all the Haskell's packaging methods (including stack and nix). If one does not care about the reproducibility/caching offered by nix, it is always possible to use cabal like in a normal system:
<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
$  nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ cabal-install ])"
$  nix-shell -p "ghc.withPackages (pkgs: [ pkgs.cabal-install ])"
$ cabal init
$ cabal init
Line 58: Line 79:
Similarly you can use [https://docs.haskellstack.org/en/stable/ Stack] that let you find the appropriate version of the libraries for you if you do not want the caching offered by nix (stack will build all the dependencies):
Similarly you can use [https://docs.haskellstack.org/en/stable/ Stack] that let you find the appropriate version of the libraries for you if you do not want the caching offered by nix (stack will build all the dependencies):
<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
$ nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ stack ])"
$ nix-shell -p "ghc.withPackages (pkgs: [ pkgs.stack ])"
$ stack new my-project
$ stack new my-project
$ cd my-project
$ cd my-project
Line 84: Line 105:
You can also use nix in place of stack to keep track of the dependencies in a reproducible way (note that while stack uses a solver to find a working set of dependencies, nix uses a fixed set of packages). Additionally you can benefit from the caching system offered by Nix. To that end, first create a cabal repository (nix also uses cabal internally):
You can also use nix in place of stack to keep track of the dependencies in a reproducible way (note that while stack uses a solver to find a working set of dependencies, nix uses a fixed set of packages). Additionally you can benefit from the caching system offered by Nix. To that end, first create a cabal repository (nix also uses cabal internally):
<syntaxhighlight lang="console">
<syntaxhighlight lang="console">
$ nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ cabal-install ])" --run "cabal init"
$ nix-shell -p "ghc.withPackages (pkgs: [ pkgs.cabal-install ])" --run "cabal init"
…  
…  
</syntaxhighlight>
</syntaxhighlight>