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

Posted

技术标签:

【中文标题】在 nix 上的 haskell 开发环境中使用 hoogle【英文标题】:Using hoogle in a haskell development environment on nix 【发布时间】:2015-02-27 23:58:02 【问题描述】:

我正在尝试在 Haskell 开发环境中使用 hoogle 就像O'Charles' wiki描述的那样:

为了使用hoogleLocal,我已经像下面这样修改了shell.nix,但它似乎没有为我安装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)))
  ];

在生成的 shell 中,hoogle 二进制文件不可用。

如果我在buildInputs 中包含hs.hoogle,则会安装hoogle 二进制文件,但它找不到数据库。以下是我尝试使用它时发生的情况。

$ 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)
$

对于 O'Charles 所描述的设置,我如何才能使其正常工作?

编辑:原来的shell.nix与this answer中的相同。

【问题讨论】:

【参考方案1】:

这是我的 Nix Haskell 开发环境的样子

~/.nixpkgs/config.nix:

环境辅助函数

首先,定义一个 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)];
  ;

定义一些环境

调用此函数来定义两种环境:一种用于在更改时运行 Hoogle 构建器,一种不用于:

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

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

定义你想在本地 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
];

外壳助手

在您的 ~/.profile 中定义几个 bash 函数以方便加载这些环境:

环境类型() 环境类型="$1" 转移 nix-shell -Q -p $envtype "$@" haskell-env () 环境类型“haskellEnv”“$@” haskell-env-hoogle () 环境类型“haskellEnvHoogle”“$@”

胡歌

在你的 shell 中调用haskell-env-hoogle。这将构建您所有的包 + 文档并将您加载到具有hoogle 范围的环境中。此时我通常会输入:

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

在后台启动一个hoogle server。最终我想为此提供一个 systemd 服务,以便我可以通过 nixos-rebuild 重新生成文档并自动启动服务器。

Emacs

对于 emacs,我将 haskell-hoogle-url 设置为 http://localhost:8080/?hoogle=%s,这样我就可以获取光标下关键字的本地 hoogle 文档。我使用 spacemacs,所以我只需键入 , h h 即可获得此功能。

您可以在此处查看我的完整 nixpkgs 配置:https://github.com/jb55/nix-files/blob/659798f2ca81fb7ad0cb5a29de576024ee16eef8/nixpkgs/config.nix#L20

希望对您有所帮助。

【讨论】:

【参考方案2】:

haskellPackages.hoogleLocal 似乎已过时;它已经不存在了。

William Casarin 的回答似乎是假设您将使用一个单一的“haskell 开发环境”,而不是使用 nix-shell 为不同的项目提供不同的开发环境。

我刚刚想出的办法是编写我的 shell.nix 以覆盖 ghc.withPackagesghcWithPackagesghc.withHoogle,这样当 nix-shell 创建一个带有 GHC 的环境时,它知道关于所有必要的包,它还会创建一个知道相同包的 hoogle 数据库。

这是我的 shell.nix1

 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

我对 nix 很陌生,但我相信这应该是“独立于项目”的;当我更改它时,我可以使用cabal2nix . &gt; default.nix 从我的 cabal 文件中生成一个 nix 包,而无需触摸 shell.nix。

我还没有真正在实际开发中使用它,只是我用来尝试弄清楚如何让 hoogle 在 nix-shell 中工作的一个虚拟项目。


1这是cabal2nix --shell 吐出的骨架,删除了项目特定的内脏并用f = import ./default.nix 替换,而不是再次嵌入nixified cabal 包。

【讨论】:

是的!我曾经这样做过。在编写大量 Haskell 代码时,我发现将所有内容都放在一个 shell 中以进行快速开发更容易。但是,如果您只有一个正在从事的项目,这将非常有用。【参考方案3】:

使用@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 );```

【讨论】:

以上是关于在 nix 上的 haskell 开发环境中使用 hoogle的主要内容,如果未能解决你的问题,请参考以下文章

您在 *nix 服务器上的 ASP.NET Core 生产环境中使用哪个 Web 服务器?

GHCup安装haskell开发环境

在 Haskell 中有效地读取和排序包含文本行的文件

我可以复制nix-build与nix-shell和cabal构建的内容吗?

如何从 nix 表达式文件中安装 nix-env 派生?

GTKWindows下Haskell的GTK开发环境搭建