Jump to content

Haskell: Difference between revisions

m
imported>Sternenseemann
(cabal2nix is not deprecated)
 
(11 intermediate revisions by 8 users not shown)
Line 1: Line 1:
== FAQ and resources ==
== FAQ and resources ==
* '''Official Docs:''' [https://nixos.org/manual/nixpkgs/unstable/#haskell '''The Haskell section in the nixpkgs manual''']


* [https://www.srid.ca/haskell-nix '''Nix recipes for Haskellers'''] aims to get a beginner comfortable managing simple Haskell programs and projects using Nix.  
* [https://www.srid.ca/haskell-nix '''Nix recipes for Haskellers'''] aims to get a beginner comfortable managing simple Haskell programs and projects using Nix.  
 
* [https://nixos.asia/en/nixify-haskell-nixpkgs '''Nixifying a Haskell project using nixpkgs'''] explains how to use Nix to package and develop Haskell projects using nothing but nixpkgs.  
* [https://haskell4nix.readthedocs.io/ '''The official documentation'''] (the [https://nixos.org/manual/nixpkgs/stable/#haskell manual] directly points to this ressource)


* [https://github.com/mhwombat/nix-for-numbskulls/blob/78bcc186f79931c0e4a1e445e2f6b1f12f6d46be/Haskell/ss-haskell-dev.md '''Super-Simple Haskell Development with Nix'''] (and [https://discourse.nixos.org/t/super-simple-haskell-development-with-nix/14287/2 discussion] that provides interesting alternative methods together with there pro and cons)
* [https://github.com/mhwombat/nix-for-numbskulls/blob/78bcc186f79931c0e4a1e445e2f6b1f12f6d46be/Haskell/ss-haskell-dev.md '''Super-Simple Haskell Development with Nix'''] (and [https://discourse.nixos.org/t/super-simple-haskell-development-with-nix/14287/2 discussion] that provides interesting alternative methods together with there pro and cons)
Line 19: Line 20:
[[File:haskell_choice.png]]
[[File:haskell_choice.png]]


Note that in the following, <code>haskellPackages</code> is a synonym of <code>haskell.packages.ghcXYZ</code> where <code>XYZ</code> is the current default version of GHC in nixpkgs. However you can use a different version by replacing <code>haskellPackages</code> with the wanted package, for instance use <code>haskell.packages.ghc884</code> to use GHC 8.8.4. You can get the full list of available GHC versions using:
Note that in the following, <code>haskellPackages</code> is a synonym of <code>haskell.packages.ghcXYZ</code> where <code>XYZ</code> is the current default version of GHC in nixpkgs. However you can use a different version by replacing <code>haskellPackages</code> with the wanted package, for instance use <code>haskell.compiler.ghc884</code> to use GHC 8.8.4. You can get the full list of available GHC versions using:


<syntaxhighlight lang="bash">
<syntaxhighlight lang="console">
$ nix-env -f "<nixpkgs>" -qaP -A haskell.compiler
$ nix-env -f "<nixpkgs>" -qaP -A haskell.compiler
haskell.compiler.ghc8107                ghc-8.10.7
haskell.compiler.ghc8107                ghc-8.10.7
Line 35: Line 36:


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 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>:
<pre>
<syntaxhighlight lang=bash>
#!/usr/bin/env nix-shell
#!/usr/bin/env nix-shell
#!nix-shell --pure -i runghc -p "haskellPackages.ghcWithPackages (pkgs: [ pkgs.turtle ])"
#!nix-shell --pure -i runghc -p "haskellPackages.ghcWithPackages (pkgs: [ pkgs.turtle ])"
Line 42: Line 43:
   # do stuff
   # do stuff
   putStrLn "Hello world from a distributable Haskell script!"
   putStrLn "Hello world from a distributable Haskell script!"
</pre>
</syntaxhighlight>


Read below if some packages are broken.
Read below if some packages are broken.
Line 48: Line 49:
=== Directly using cabal (no nix caching/reproducibility) ===
=== Directly using cabal (no nix caching/reproducibility) ===
Note that 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:
Note that 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:
<pre>
<syntaxhighlight lang="console">
$  nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ cabal-install ])"
$  nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ cabal-install ])"
$ cabal init
$ cabal init
Line 55: Line 56:
Up to date
Up to date
Hello, Haskell!
Hello, Haskell!
</pre>
</syntaxhighlight>


Note that some packages may need additional libraries/programs, notably <code>zlib</code>, you should be able to add them as additional programs in the nix-shell option.
Notes:
* some packages may need additional libraries/programs, notably <code>zlib</code>, you should be able to add them as additional programs in the nix-shell option
* since Cabal 2.0, cabal has acquired caching similar to nix (but not as powerful) and reproducibility (via the cabal.project file and the index-state option). See [https://cabal.readthedocs.io/en/stable/cabal-project.html#cfg-field-index-state] for more information.


=== Using Stack (no nix caching) ===
=== Using Stack (no nix caching) ===


Similarly you can use 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 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):
<pre>
<syntaxhighlight lang="console">
$ nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ stack ])"
$ nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ stack ])"
$ stack new my-project
$ stack new my-project
Line 68: Line 71:
$ stack build
$ stack build
$ stack exec my-project-exe
$ stack exec my-project-exe
</pre>
</syntaxhighlight>


You can also use the features offered by stack to enable nix integration in order to use nix to install the non-haskell dependencies. You can read more [https://docs.haskellstack.org/en/stable/nix_integration/ here].
You can also use the features offered by stack to enable nix integration in order to use nix to install the non-haskell dependencies. You can read more [https://docs.haskellstack.org/en/stable/nix_integration/ here].
Line 81: Line 84:
}
}
</syntaxhighlight>
</syntaxhighlight>
'''Disclaimer''': For users of a stable version of NixOS there could be a problem where Stack tries to use a GHC version that is not yet in the given channel of Nixpkgs. Example at the time of writing: When using NixOS 23.05, Stack defaults to using the LTS-21.10 resolver, which uses <code>ghc-9.4.6</code>. However, the newest version of GHC in the 23.05 channel is <code>ghc-9.4.4</code>, thus Stack fails to execute some commands.
As a solution, [https://docs.haskellstack.org/en/stable/yaml_configuration/#resolver-or-snapshot specify a resolver in your <code>stack.yaml</code>] file that uses a GHC version available for your channel. You can find a list of snapshots on https://www.stackage.org/snapshots. Or alternatively, set the resolver as a command line argument, which is required for running commands such as <code>stack new</code>.


===  Using developPackage (use the nix packages set for haskell) ===
===  Using developPackage (use the nix packages set for haskell) ===


You can use also 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 use also 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="nix">
<syntaxhighlight lang="console">
$ nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ cabal-install ])" --run "cabal init"
$ nix-shell -p "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ cabal-install ])" --run "cabal init"
…  
…  
Line 103: Line 110:


Then you can build and run the program using:
Then you can build and run the program using:
<pre>
<syntaxhighlight lang="console">
$ nix-build
$ nix-build
$ ./result/bin/yourprogram  
$ ./result/bin/yourprogram  
</pre>
</syntaxhighlight>
or run a nix-shell to use the standard development tools provided by cabal:
or run a nix-shell to use the standard development tools provided by cabal:
<pre>
<syntaxhighlight lang="console">
$ nix-build
$ nix-build
$ ./result/bin/yourprogram  
$ ./result/bin/yourprogram  
</pre>
</syntaxhighlight>


Nix will automatically read the <code>build-depends</code> field in the <code>*.cabal</code> file to get the name of the dependencies and use the haskell packages provided in the configured package set provided by nix. Note that some of the packages present in the nix repository are broken (for instance because a package requires an older version of a library while nix only provides a recent version). For this reason it may be necessary to override some packages present in the nix package set as described below using the <code>overrides</code> and <code>source-overrides</code> attribute. Note that the <code>source-overrides</code> attribute can also turn out to be useful to load local libraries:
Nix will automatically read the <code>build-depends</code> field in the <code>*.cabal</code> file to get the name of the dependencies and use the haskell packages provided in the configured package set provided by nix. Note that some of the packages present in the nix repository are broken (for instance because a package requires an older version of a library while nix only provides a recent version). For this reason it may be necessary to override some packages present in the nix package set as described below using the <code>overrides</code> and <code>source-overrides</code> attribute. Note that the <code>source-overrides</code> attribute can also turn out to be useful to load local libraries:
Line 155: Line 162:
For instance you can define your various projects in subfolders <code>./frontend</code> and <code>./backend</code> (you can use cabal init to create the content in each folder), then create a file <code>cabal.project</code> containing:
For instance you can define your various projects in subfolders <code>./frontend</code> and <code>./backend</code> (you can use cabal init to create the content in each folder), then create a file <code>cabal.project</code> containing:


<syntaxhighlight>
<syntaxhighlight lang=text>
packages:
packages:
   frontend/
   frontend/
Line 180: Line 187:
then you can use cabal to develop incrementally your projects using for instance:
then you can use cabal to develop incrementally your projects using for instance:


<syntaxhighlight lang="bash">
<syntaxhighlight lang="console">
$ nix-shell
$ nix-shell
$ cabal new-build all
$ cabal new-build all
Line 198: Line 205:
=== Using haskell.nix (for complex projects) ===
=== Using haskell.nix (for complex projects) ===


The [https://github.com/input-output-hk/haskell.nix haskell.nix] project allows you to have maximum flexibility (to create your own package set or use in teams with diverse people, some of them using stack, other using cabal, other using nix…). But this comes at the price of an additional complexity.
The [https://github.com/input-output-hk/haskell.nix haskell.nix] project allows you to have maximum flexibility (to create your own package set or use in teams with diverse people, some of them using stack, other using cabal, other using nix…). But this comes at the price of additional complexity.
 
=== Using haskell-flake (flake-parts) ===
 
[https://community.flake.parts/haskell-flake haskell-flake] aims to simplify writing Nix for Haskell development through use of flake-parts module system. It uses <code>callCabal2nix</code> and <code>shellFor</code> under the hood while exposing friendly module options API.


== Overrides ==
== Overrides ==
5

edits