简体   繁体   English

在nix上的haskell开发环境中使用hoogle

[英]Using hoogle in a haskell development environment on nix

I'm trying to use hoogle in a Haskell development environment exactly like the one described by O'Charles' wiki : 我试图在Haskell开发环境中使用hoogle,就像O'Charles的wiki所描述的那样:

I have modified shell.nix like below in order to use hoogleLocal , but it doesn't seem to install the hoogle binary for me. 我已经修改了shell.nix如下所示,以便使用hoogleLocal ,但它似乎没有为我安装hoogle二进制文件。

let
  pkgs = import <nixpkgs> {};

  # I'm attempting to use hoogle here, but it is not working.
  haskellPackages =
    let callPackage = pkgs.lib.callPackageWith haskellPackages;
    in pkgs.recurseIntoAttrs (pkgs.haskellPackages.override {
      extension = self: super: {
        thiscurrentpackage = self.callPackage ./. {};
        hoogleLocal = pkgs.haskellPackages.hoogleLocal.override {
          packages = self.thiscurrentpackage;
        };
      };
    });
in pkgs.myEnvFun {
  name = haskellPackages.thiscurrentpackage.name;
  buildInputs = [
    (haskellPackages.ghcWithPackages (hs: ([
      hs.cabalInstall
      hs.ghcMod
      hs.yesodBin
      # This doesn't appear to install the hoogle binary?
      hs.hoogleLocal
    ] ++ hs.thiscurrentpackage.propagatedNativeBuildInputs)))
  ];
}

In the resulting shell, the hoogle binary is not available. 在生成的shell中, hoogle二进制文件不可用。

If I include hs.hoogle to the buildInputs , the hoogle binary is installed but it can't find the databases. 如果我将hs.hoogle包含在buildInputs ,则会安装hoogle二进制文件,但无法找到数据库。 Below is what happens when I try to use it. 以下是我尝试使用它时会发生的情况。

$ nix-shell
......
$ hoogle Monad
Could not find some databases: default
Searching in:
  .
    /nix/store/91y9q2y5a2ws8xgcsx1gkhfagc0f2qz6-haskell-hoogle-ghc7.8.3-4.2.36-shared/share/x86_64-linux-ghc-7.8.3/hoogle-4.2.36/databases

    There are no available databases, generate them with: hoogle data
$ hoogle data
    hoogle: /nix/store/91y9q2y5a2ws8xgcsx1gkhfagc0f2qz6-haskell-hoogle-ghc7.8.3-4.2.36-shared/share/x86_64-linux-ghc-7.8.3/hoogle-4.2.36/databases:
changeWorkingDirectory: does not exist (No such file or directory)
$

How do I get this working correctly for a setup like described by O'Charles? 如何正确使用O'Charles描述的设置?

Edit : The original shell.nix is the same one from this answer . 编辑 :原始shell.nix与此答案中的相同。

Here's what my Nix Haskell dev environment looks like 这是我的Nix Haskell开发环境的样子

in ~/.nixpkgs/config.nix : ~/.nixpkgs/config.nix

The environment helper function 环境助手功能

First off, define a haskellEnvFun function for building Haskell environments: 首先,定义一个haskellEnvFun函数来构建Haskell环境:

packageOverrides = super: rec {

haskellEnvFun = { withHoogle ? false, compiler ? null, name }:
  let hp = if compiler != null
             then super.haskell.packages.${compiler}
             else haskellPackages;

      ghcWith = if withHoogle
                  then hp.ghcWithHoogle
                  else hp.ghcWithPackages;

  in super.buildEnv {
    name = name;
    paths = [(ghcWith myHaskellPackages)];
  };

Defining some environments 定义一些环境

Call this function to define two environments: one for running the Hoogle builder on changes, and one without: 调用此函数可以定义两个环境:一个用于在更改时运行Hoogle构建器,另一个用于:

haskellEnvHoogle = haskellEnvFun {
  name = "haskellEnvHoogle";
  withHoogle = true;
};

haskellEnv = haskellEnvFun {
  name = "haskellEnv";
  withHoogle = false;
};

Packages

Define all the packages you want to use in your local Haskell dev environment: 定义要在本地Haskell开发环境中使用的所有包:

myHaskellPackages = hp: with hp; [
  Boolean
  HTTP
  HUnit
  MissingH
  QuickCheck
  SafeSemaphore
  Spock
  aeson
  async
  attoparsec
  bifunctors
  blaze-builder
  blaze-builder-conduit
  blaze-builder-enumerator
  blaze-html
  blaze-markup
  blaze-textual
  cased
  cassava
  cereal
  comonad
  comonad-transformers
  directory_1_2_4_0
  dlist
  dlist-instances
  doctest
  exceptions
  fingertree
  foldl
  free
  hamlet
  hashable
  hspec
  hspec-expectations
  html
  http-client
  http-date
  http-types
  io-memoize
  keys
  language-c
  language-javascript
  language-bash
  lens
  lens-action
  lens-aeson
  lens-datetime
  lens-family
  lens-family-core
  lifted-async
  lifted-base
  linear
  list-extras
  list-t
  logict
  mime-mail
  mime-types
  mmorph
  monad-control
  monad-coroutine
  monad-loops
  monad-par
  monad-par-extras
  monad-stm
  monadloc
  mongoDB
  monoid-extras
  network
  newtype
  numbers
  optparse-applicative
  parsec
  parsers
  pcg-random
  persistent
  persistent-mongoDB
  persistent-template
  pipes
  pipes-async
  pipes-attoparsec
  pipes-binary
  pipes-bytestring
  pipes-concurrency
  pipes-csv
  pipes-extras
  pipes-group
  pipes-http
  pipes-mongodb
  pipes-network
  pipes-parse
  pipes-safe
  pipes-shell
  pipes-text
  posix-paths
  postgresql-simple
  pretty-show
  profunctors
  random
  reducers
  reflection
  regex-applicative
  regex-base
  regex-compat
  regex-posix
  regular
  relational-record
  resourcet
  retry
  rex
  safe
  sbv
  scotty
  semigroupoids
  semigroups
  shake
  shakespeare
  shelly
  simple-reflect
  speculation
  split
  spoon
  stm
  stm-chans
  stm-stats
  streaming
  streaming-bytestring
  streaming-wai
  strict
  stringsearch
  strptime
  syb
  system-fileio
  system-filepath
  tagged
  taggy
  taggy-lens
  tar
  tardis
  tasty
  tasty-hspec
  tasty-hunit
  tasty-quickcheck
  tasty-smallcheck
  temporary
  test-framework
  test-framework-hunit
  text
  text-format
  time
  tinytemplate
  transformers
  transformers-base
  turtle
  uniplate
  unix-compat
  unordered-containers
  uuid
  vector
  void
  wai
  wai-conduit
  warp
  wreq
  xhtml
  yaml
  zippers
  zlib
];

Shell helpers 壳牌助手

In your ~/.profile define a couple bash functions to load those environments for convenience: ~/.profile定义了几个bash函数来加载这些环境以方便:

env-type () {
  envtype="$1"
  shift
  nix-shell -Q -p $envtype "$@"
}

haskell-env () {
  env-type "haskellEnv" "$@"
}

haskell-env-hoogle () {
  env-type "haskellEnvHoogle" "$@"
}

Hoogle Hoogle

Call haskell-env-hoogle in your shell. 在你的shell中调用haskell-env-hoogle This will build all of your packages + docs and load you into an environment with hoogle in scope. 这将构建您的所有软件包+文档,并将您加载到范围为hoogle的环境中。 At this point I usually type: 此时我通常输入:

hoogle server --local -p 8080 &> /tmp/hoogle.log & disown

to launch a hoogle server the the background. 启动一个hoogle服务器的后台。 Eventually I want to have a systemd service for this so that I can just nixos-rebuild to regen docs and launch the server automatically. 最终我希望有一个systemd服务,这样我就可以通过nixos-rebuild重新生成文档并自动启动服务器。

Emacs Emacs的

For emacs I've set the haskell-hoogle-url to http://localhost:8080/?hoogle=%s , so that I can get local hoogle docs for keywords under my cursor. 对于emacs,我已经将haskell-hoogle-urlhttp://localhost:8080/?hoogle=%s ,这样我就可以在光标下获取关键字的本地hoogle文档。 I use spacemacs so I just type , hh for this functionality. 我使用spacemacs所以我只是键入, hh这个功能。

You can see my full nixpkgs config here: https://github.com/jb55/nix-files/blob/659798f2ca81fb7ad0cb5a29de576024ee16eef8/nixpkgs/config.nix#L20 你可以在这里看到我的完整nixpkgs配置: https//github.com/jb55/nix-files/blob/659798f2ca81fb7ad0cb5a29de576024ee16eef8/nixpkgs/config.nix#L20

Hope that helps. 希望有所帮助。

haskellPackages.hoogleLocal appears to be out of date; haskellPackages.hoogleLocal似乎已过时; it doesn't exist anymore. 它不再存在了。

William Casarin's answer appears to be assuming you will have a single "haskell development environment" you use, rather than using nix-shell to have different dev environments for different projects. William Casarin的回答似乎是假设您将使用单个“haskell开发环境”,而不是使用nix-shell为不同的项目设置不同的开发环境。

What I've just figured out how to do instead is to write my shell.nix to override ghc.withPackages and ghcWithPackages to be ghc.withHoogle , so that when nix-shell creates an environment with a GHC that knows about all the necessary packages it also creates a hoogle database that knows about the same packages. 我刚刚弄清楚如何做的是编写我的shell.nix以覆盖ghc.withPackagesghcWithPackagesghc.withHoogle ,这样当nix-shell创建一个GHC环境时,它知道所有必需的包它还创建了一个知道相同包的hoogle数据库。

Here's my shell.nix 1 : 这是我的shell.nix 1

{ nixpkgs ? import <nixpkgs> {}, compiler ? "default", withHoogle ? true }:

let

  inherit (nixpkgs) pkgs;

  f = import ./default.nix;

  packageSet = (
    if compiler == "default"
      then  pkgs.haskellPackages
      else  pkgs.haskell.packages.${compiler}
  );

  haskellPackages = (
    if withHoogle
      then  packageSet.override {
              overrides = (self: super:
                {
                  ghc = super.ghc // { withPackages = super.ghc.withHoogle; };
                  ghcWithPackages = self.ghc.withPackages;
                }
              );
            }
      else  packageSet
  );

  drv = haskellPackages.callPackage f {};

in

  if pkgs.lib.inNixShell then drv.env else drv

I'm newish to nix, but I believe this should be pretty much "project independent"; 我对nix很新,但我相信这应该是“项目独立的”; I can use cabal2nix . > default.nix 我可以使用cabal2nix . > default.nix cabal2nix . > default.nix to generate a nix package from my cabal file when I change it, without having to touch shell.nix. cabal2nix . > default.nix在我更改它时从我的cabal文件生成一个nix包,而不必触及shell.nix。

I haven't actually used this in real development yet, only a dummy project I was using to try to figure out how to get hoogle working in nix-shell. 我还没有在实际开发中实际使用它,只是我用来试图找出如何让nogle-shell中的hoogle工作的虚拟项目。


1 The skeleton of this was what cabal2nix --shell spits out, with the project-specific guts removed and replaced with f = import ./default.nix instead of embedding the nixified cabal package again. 1这个的骨架是cabal2nix --shell吐出来的,删除了项目特定的内容并用f = import ./default.nix替换,而不是再次嵌入nixified cabal包。

Using @Ben's answer as reference, here is a diff on the required changes I needed to make to a cabal2nix --shell file: 使用@ Ben的答案作为参考,这是我需要对cabal2nix --shell文件进行必要更改的差异:

diff --git a/shell.nix b/shell.nix
index 540ade3..e207d6e 100644
--- a/shell.nix
+++ b/shell.nix
@@ -1,4 +1,4 @@
-{ nixpkgs ? import <nixpkgs> {}, compiler ? "default", doBenchmark ? false }:
+{ nixpkgs ? import <nixpkgs> {}, compiler ? "default", doBenchmark ? false , withHoogle ? true}:

 let

@@ -21,10 +21,23 @@ let
         license = stdenv.lib.licenses.bsd3;
       };

-  haskellPackages = if compiler == "default"
+  haskellPackages' = if compiler == "default"
                        then pkgs.haskellPackages
                        else pkgs.haskell.packages.${compiler};

+  haskellPackages = (
+    if withHoogle
+    then  haskellPackages'.override {
+      overrides = (self: super:
+        {
+          ghc = super.ghc // { withPackages = super.ghc.withHoogle; };
+          ghcWithPackages = self.ghc.withPackages;
+        }
+      );
+    }
+    else haskellPackages'
+  );
+
   variant = if doBenchmark then pkgs.haskell.lib.doBenchmark else pkgs.lib.id;

   drv = variant (haskellPackages.callPackage f {});```

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM