Подтвердить что ты не робот

Как сделать проект каскада Haskell с библиотекой + исполняемыми файлами, которые все еще работают с runhaskell/ghci?

Если вы объявите библиотеку + исполняемые разделы в файле cabal, избегая двойной компиляции библиотеки, поместив библиотеку в каталог hs-source-dirs, вы обычно не можете запустите проект ghci и runhaskell, особенно если исполняемые файлы имеют собственные вспомогательные модули.

Что такое рекомендуемый макет проекта, который

  • создает только то, что нужно
  • позволяет использовать runhaskell
  • имеет чистую структуру без хаков?
4b9b3361

Ответ 1

Предположим, что у вас есть библиотека mylib и mylib-commandline и mylib-server исполняемые файлы.

Вы используете hs-source-dirs для библиотеки и каждого исполняемого файла, чтобы каждый из них имел свой собственный корень проекта, избегая двойной компиляции:

mylib/                      # Project root
  mylib.cabal
  src/                      # Root for the library
  tests/
  mylib-commandline/        # Root for the command line utility + helper modules
  mylib-server/             # Root for the web service + helper modules

Полный макет каталога:

mylib/                      # Project root
  mylib.cabal
  src/                      # Root for the library
    Web/
      Mylib.hs              # Main library module
      Mylib/
        ModuleA             # Mylib.ModuleA
        ModuleB             # Mylib.ModuleB
  tests/
    ...
  mylib-commandline/        # Root for the command line utility
    Main.hs                 # "module Main where" stub with "main = Web.Mylib.Commandline.Main.main"
    Web/
      Mylib/
        Commandline/
          Main.hs           # CLI entry point
          Arguments.hs      # Programm command line arguments parser
  mylib-server/             # Root for the web service
    Server.hs               # "module Main where" stub with "main = Web.Mylib.Server.Main.main"
    Web/
      Mylib/
        Server/
          Main.hs           # Server entry point
          Arguments.hs      # Server command line arguments parser

Этот файл-заглушка mylib-commandline/Main.hs выглядит следующим образом:

module Main where

import qualified Web.Mylib.Server.Main as MylibServer

main :: IO ()
main = MylibServer.main

Вам нужны они, потому что executable должен начинаться с модуля, просто называемого Main.

Ваш mylib.cabal выглядит следующим образом:

library
  hs-source-dirs:   src
  exposed-modules:
    Web.Mylib
    Web.Mylib.ModuleA
    Web.Mylib.ModuleB
  build-depends:
      base >= 4 && <= 5
    , [other dependencies of the library]

executable mylib-commandline
  hs-source-dirs:   mylib-commandline
  main-is:          Main.hs
  other-modules:
    Web.Mylib.Commandline.Main
    Web.Mylib.Commandline.Arguments
  build-depends:
      base >= 4 && <= 5
    , mylib
    , [other depencencies for the CLI]

executable mylib-server
  hs-source-dirs:   mylib-server
  main-is:          Server.hs
  other-modules:
    Web.Mylib.Server.Main
  build-depends:
      base >= 4 && <= 5
    , mylib
    , warp >= X.X
    , [other dependencies for the server]

cabal build построит библиотеку и два исполняемых файла без двойной компиляции библиотеки, поскольку каждый из них находится в своем собственном hs-source-dirs, а исполняемые файлы зависят от библиотеки.

Вы все равно можете запускать исполняемые файлы с помощью runghc из корня проекта, используя переключатель -i, чтобы указать, где он должен искать модули (используя : в качестве разделителя):

runhaskell -isrc:mylib-commandline mylib-commandline/Main.hs

runhaskell -isrc:mylib-server mylib-server/Server.hs

Таким образом, вы можете иметь чистый макет, исполняемые файлы с вспомогательными модулями, и все по-прежнему работает с runhaskell/runghc и ghci. Чтобы не печатать этот флаг повторно, вы можете добавить что-то похожее на

:set -isrc:mylib-commandline:mylib-server

в ваш .ghci файл.


Обратите внимание, что иногда нужно разделить свой код на отдельные пакеты, например. mylib, mylib-commandline и mylib-server.

Ответ 2

Вы можете использовать cabal repl для запуска ghci с конфигурацией из файла cabal и cabal run для компиляции и запуска исполняемых файлов. В отличие от runhaskell и ghci, использование cabal repl и cabal run также правильно забирает зависимости из песочницы cabal.