Haskell: Difference between revisions
imported from old wiki |
m Use lang=haskell for syntax highlight |
||
(8 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
[https://www.haskell.org/ Haskell] is a statically-typed, purely functional programming language with strong support for type inference and lazy evaluation. | |||
For detailed information on Haskell support in Nixpkgs, refer to the official {{Nixpkgs Manual|name=Nixpkgs Manual: Chapter - Haskell|anchor=#haskell}}. | |||
== How to develop with Haskell and Nix == | == How to develop with Haskell and Nix == | ||
Line 20: | Line 9: | ||
[[File:haskell_choice.png]] | [[File:haskell_choice.png]] | ||
Note | {{Note|{{nixos:package|haskellPackages}} 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="console"> | <syntaxhighlight lang="console"> | ||
Line 32: | Line 21: | ||
… | … | ||
</syntaxhighlight> | </syntaxhighlight> | ||
}} | |||
=== 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 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>: | ||
<syntaxhighlight lang= | <syntaxhighlight lang=haskell> | ||
#!/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 ])" | ||
main = do | main = do | ||
-- do stuff | |||
putStrLn "Hello world from a distributable Haskell script!" | putStrLn "Hello world from a distributable Haskell script!" | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Read | To write inline Haskell scripts in nix-code, refer to [[Nix-writers#Haskell]]. | ||
Read [[#Overrides]] if some packages are broken. | |||
=== Directly using cabal (no nix caching/reproducibility) === | === Directly using cabal (no nix caching/reproducibility) === | ||
[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 "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ cabal-install ])" | ||
Line 58: | Line 51: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
{{note|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.}} | |||
{{note|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/latest/cabal-project-description-file.html#cfg-field-index-state] for more information.}} | |||
=== Using Stack (no nix caching) === | === Using Stack (no nix caching) === | ||
Similarly you can use | 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 "haskellPackages.ghcWithPackages (pkgs: with pkgs; [ stack ])" | ||
Line 85: | Line 77: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
{{note|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.<br/> | |||
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>.}} | |||
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) === | ||
Line 116: | Line 107: | ||
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: | ||
<syntaxhighlight lang="console"> | <syntaxhighlight lang="console"> | ||
$ nix- | $ nix-shell | ||
$ | $ cabal run | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 152: | Line 143: | ||
You can also get more details | You can also get more details in [https://github.com/NixOS/nixpkgs/blob/0ba44a03f620806a2558a699dba143e6cf9858db/pkgs/development/haskell-modules/make-package-set.nix#L230 pkgs/development/haskell-modules/make-package-set.nix]. | ||
=== Using shellFor (multiple packages) === | === Using shellFor (multiple packages) === | ||
Line 209: | Line 200: | ||
=== Using haskell-flake (flake-parts) === | === Using haskell-flake (flake-parts) === | ||
[https://flake.parts | [https://community.flake.parts/haskell-flake haskell-flake] is a project that aims to simplify writing Nix for Haskell development through use of [[Flake Parts|flake-parts module system]]. It uses <code>callCabal2nix</code> and <code>shellFor</code> under the hood while exposing friendly module options API. For an overview of Flakes, see the [[Flakes]] wiki page. | ||
* For existing Haskell projects, initialize with: | |||
<syntaxhighlight lang="bash"> | |||
nix flake init -t github:srid/haskell-flake | |||
</syntaxhighlight> | |||
* For new Haskell projects, use the example template: | |||
<syntaxhighlight lang="bash"> | |||
mkdir example && cd ./example | |||
nix flake init -t github:srid/haskell-flake#example | |||
</syntaxhighlight> | |||
This command will generate a project template with additional configuration details, comments, and examples. Below is an example minimal flake definition for a simple project: | |||
{{file|flake.nix|nix| | |||
<nowiki> | |||
{ | |||
inputs = { | |||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; | |||
flake-parts.url = "github:hercules-ci/flake-parts"; | |||
haskell-flake.url = "github:srid/haskell-flake"; | |||
}; | |||
outputs = inputs@{ self, nixpkgs, flake-parts, ... }: | |||
flake-parts.lib.mkFlake { inherit inputs; } { | |||
systems = nixpkgs.lib.systems.flakeExposed; | |||
imports = [ inputs.haskell-flake.flakeModule ]; | |||
perSystem = { self', pkgs, ... }: { | |||
haskellProjects.default = { | |||
# Project configurations such as GHC version and package overrides are defined here | |||
# See: https://flake.parts/options/haskell-flake | |||
}; | |||
# haskell-flake doesn't set the default package, but you can do it here. | |||
packages.default = self'.packages.example; | |||
}; | |||
}; | |||
} | |||
</nowiki> | |||
}} | |||
Once configured, you can build and run the project with: | |||
<syntaxhighlight lang="console"> | |||
$ nix build # Build the project; the binary will be placed in ./result/bin | |||
$ ./result/bin/example | |||
$ nix run # Alternatively, run the default executable directly | |||
</syntaxhighlight> | |||
or enter a development shell to use the standard development tools provided by the flake: | |||
<syntaxhighlight lang="console"> | |||
$ nix develop | |||
$ cabal run | |||
</syntaxhighlight> | |||
The build process will use the <code>example.cabal</code> file and run the executable defined within it. A current limitation is that if your Cabal file contains multiple <code>executable</code> blocks, you can only assign one as the default package. This limitation also applies when using a <code>cabal.project</code>. To run a specific executable by name, use the following command <code>nix run .#another-example</code>. Below is an example cabal file defining two executables: | |||
{{file|example.cabal|haskell| | |||
<nowiki> | |||
executable example | |||
main-is: Main.hs | |||
... | |||
executable another-example | |||
main-is: AnotherMain.hs | |||
... | |||
</nowiki> | |||
}} | |||
==== Further reading ==== | |||
* [https://github.com/srid/haskell-template/tree/master Example Haskell project with a development environment] | |||
* [https://github.com/srid/haskell-multi-nix/tree/master Example cabal.project multi-package Haskell project] | |||
* [https://community.flake.parts/haskell-flake/start Getting started with haskell-flake]. | |||
* [https://community.flake.parts/haskell-flake/dependency Overriding dependencies in a haskell-flake] | |||
* [https://flake.parts/options/haskell-flake haskell-flake haskell-flake options reference] | |||
== Overrides == | == Overrides == | ||
Line 304: | Line 377: | ||
== Limitations == | == Limitations == | ||
=== cabal2nix === | |||
When using the <code>cabal2nix</code> tool, Nix does not pull a cabal package by respecting the constraint specified in the cabal file (see [https://github.com/chrissound/Cabal2NixLimitationExample example]). Issue is discussed [https://stackoverflow.com/questions/57441156/pulling-in-specific-haskell-packages-cabal-dependencies-with-nix here]. You should be using <code>callCabal2nix</code> anyway. | |||
<code>callCabal2nix</code>, which is implicitly used for building Haskell projects, uses IFD.[https://github.com/NixOS/templates/issues/28][https://discourse.nixos.org/t/another-simple-flake-for-haskell-development/18164/6]. This means that since IFD is disabled by default in certain nix commands,[https://github.com/NixOS/nix/pull/5253] the following commands will be broken for Haskell projects whose flake output specifies multiple system attributes: | === IFD and Haskell === | ||
<code>callCabal2nix</code>, which is implicitly used for building Haskell projects, uses IFD. Refer to this [https://github.com/NixOS/templates/issues/28 github issue] and [https://discourse.nixos.org/t/another-simple-flake-for-haskell-development/18164/6 discourse thread] for additional context. This means that since IFD is disabled by default in certain nix commands,[https://github.com/NixOS/nix/pull/5253] the following commands will be broken for Haskell projects whose flake output specifies multiple system attributes: | |||
* <code>nix flake show</code> | * <code>nix flake show</code> | ||
* <code>nix flake check</code> | * <code>nix flake check</code> | ||
=== GHCup === | |||
[https://www.haskell.org/ghcup/ GHCup] does not work properly on NixOS out of the box. NixOS cannot run dynamically linked executables built for generic Linux environments due to its runtime linker setup. For details and a workaround, see [https://nix.dev/guides/faq#how-to-run-non-nix-executables nix.dev's explanation of stub-ld]. | |||
In most cases there is little reason to use GHCup when working within a Nix-based system, as Nixpkgs can achieve the same goals such as managing multiple GHC versions and other Haskell tooling. | |||
== FAQ and resources == | |||
* '''Official Docs:''' [https://nixos.org/manual/nixpkgs/unstable/#haskell '''The Haskell section in the nixpkgs manual'''] | |||
* [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://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://discourse.nixos.org/t/nix-haskell-development-2020/6170 '''Nix Haskell Development (2020)'''] | |||
* [https://discourse.nixos.org/t/haskellpackages-stm-containers-fails-to-build/5416/4 '''How are Haskell packages managed in nixpkgs?'''] | |||
* [https://www.youtube.com/watch?v=KLhkAEk8I20 '''How to fix broken Haskell packages?''' (video)] | |||
[[Category:Languages]] | [[Category:Languages]] | ||
[[Category: | [[Category:Haskell]] |