Почему GHCi понимает импорт, которого нет у GHC?

#haskell #ghc #ghci

#haskell #ghc #ghci

Вопрос:

Я довольно новичок в Haskell, и я думаю, что у меня где-то есть фундаментальное недоразумение. Когда я нахожусь в GHCi (используя ghci команду), я могу печатать import System.Random , и это работает. Затем я могу генерировать случайные числа.

Затем я создаю файл с именем test.hs , который не содержит ничего, кроме одной строки: import System.Random . Затем я вызываю команду ghc test.hs и получаю следующее сообщение об ошибке:

 test.hs:1:1: error:
    Could not find module ‘System.Random’
    There are files missing in the ‘random-1.1’ package,
    try running 'ghc-pkg check'.
    Use -v to see a list of the files searched for.
  |
1 | import System.Random
  | ^^^^^^^^^^^^^^^^^^^^
  

Однако, если я вернусь к GHCi, я смогу печатать :load test.hs . Это работает и позволяет мне генерировать случайные числа.

Когда я запускаю ghc-pkg check , я получаю только предупреждения об отсутствующих файлах интерфейса haddock: https://pastebin.com/6a9f0nYZ . Насколько я понимаю, это не связано с текущей проблемой.

Кроме того, когда я запускаю ghc-pkg list , random-1.1 находится в списке, поэтому random должен быть установлен.

Пара вопросов:

  • Почему GHC и GHCi имеют доступ к разным импортам? Почему система настроена таким образом? Может быть, я просто не понимаю взаимосвязи между GHC и GHCi.
  • Согласно сообщению об ошибке, «отсутствуют файлы». Как я могу определить, какие файлы?
  • Как я могу сделать так, чтобы я мог компилировать файлы Haskell, которые используют System.Random ?

Редактировать: и GHC, и GHCi — это одна и та же версия.

 $ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.6.4
$ ghci --version
The Glorious Glasgow Haskell Compilation System, version 8.6.4
  

Редактировать: оба ghc и ghci находятся в /usr/bin/

 $ which ghc
/usr/bin/ghc
$ which ghci
/usr/bin/ghci
  

Комментарии:

1. Это разные версии?

2. Обе версии 8.6.4

3. Что делать which ghc и which ghci показывать? Я полагаю, у вас могут быть установлены две копии haskell, одна из которых повреждена.

4. @amalloy оба /usr/bin/ включены. Как я могу выяснить, установлены ли / где / как у меня две копии Haskell?

Ответ №1:

Обновление: похоже, что это особенность Arch Linux, а не поврежденный пакет. Я соответствующим образом обновил свой ответ.

GHCi загружает «динамические» версии модулей. По умолчанию GHC связывается со «статическими» версиями модулей. В частности, когда вы запускаете:

 > import System.Random
  

в GHCi он пытается получить доступ к файлу Random.dyn_hi , чтобы получить информацию об интерфейсе для модуля. Напротив, когда вы компилируете файл с этим оператором импорта в нем, GHC пытается получить доступ к файлу Random.hi .

Вы можете убедиться, что это проблема, запустив ghc-pkg field random import-dirs и заглянув в результирующий каталог. Должен быть System подкаталог, в котором обычно есть два файла: System.hi и System.dyn_hi . Если первое отсутствует, это ваша проблема.

Теперь, похоже, вы, вероятно, используете Arch Linux. Как описано на вики-странице Arch Haskell в разделе «Проблемы со связыванием», пакеты сообщества Arch Haskell (включая haskell-random ) намеренно опускают статические версии файлов интерфейса и библиотек.

Там приведено несколько обходных путей:

  • Вы можете использовать динамическое связывание при компиляции с GHC. При прямом использовании GHC это просто означает передачу -dynamic флага. Для проектов, основанных на Cabal, на этой странице даны инструкции по изменению ~/.cabal/config использования динамических ссылок для всех проектов.
  • Вы можете установить ghc-static ghc-pristine пакеты and и настроить свой path и / или Cabal для использования компилятора, в /usr/share/ghc-pristine/bin/ghc котором будет поддерживаться своя отдельная база данных пакетов, которая не будет мешать глобально установленным пакетам сообщества Haskell, например haskell-random .
  • Вы можете установить ghc-static , чтобы получить статические версии базовых библиотек, а затем запустить cabal install --force-reinstalls somepackage для всех неосновных пакетов, которые вам нужны. Обратите внимание, что вики отмечает, что это может быть утомительным и сложным, поскольку вам нужно вручную определять все зависимости пакетов.

Теперь, похоже, вы уже ghc-static установили, или при вызове GHC вы также получили бы сообщение об ошибке об отсутствующих файлах в base пакете. Вы запустили cabal install --force-reinstalls random , хотя, как отмечает @dfeuer, возможно, было бы безопаснее запускать:

 $ cabal install --force-reinstalls random-1.1
  

чтобы убедиться, что была переустановлена та же версия.

В любом случае, это установило дополнительную копию random в ваш пользовательский каталог пакетов. Если вы запустите:

 $ ghc-pkg list
  

вы увидите, что random-1.1 это указано как в глобальной базе данных, так и в базе данных пользователя:

 /usr/lib/ghc-8.6.4/package.conf.d
    ...
    random-1.1
    ...
/home/xxxx/.ghc/x86_64-linux-8.6.4/package.conf.d
    random-1.1
  

и если вы запустите:

 $ ghc-pkg describe random
  

вы увидите, что в нем перечислены две отдельные установленные версии, поэтому теперь вы получаете повторяющиеся поля ghc-pkg field random import-dirs .

В этом не должно быть ничего плохого. Ваша пользовательская база данных будет иметь приоритет над глобальной базой данных, поэтому ваша недавно установленная версия random будет использоваться при запуске GHCi или GHC.

Обратите внимание, что, если вы передумаете и захотите отказаться от этой переустановки (и, возможно, попробовать одно из других решений, предложенных в Вики), вы должны иметь возможность запускать:

 $ ghc-pkg unregister --user random
  

Технически, это фактически не приведет к удалению пакета (поскольку скомпилированная версия все еще будет там ~/.cabal/lib ), но в противном случае все должно быть так, как было.

Комментарии:

1. Чтобы избежать поломок, вы можете указать ту же версию пакета, которая уже установлена.

2. Вы точно знаете, что Random.dyn_hi существует, но Random.hi не существует. Я выполнил команду cabal install --force-reinstall random , и теперь я могу скомпилировать файлы, которые импортируются System.Random с помощью ghc команды. Однако теперь, когда я запускаю ghc-pkg field random import-dirs , я получаю две строки вывода: import-dirs: /home/finn/.cabal/lib/x86_64-linux-ghc-8.6.4/random-1.1-3ypV4EIycgb35PKjTYYr5q и import-dirs: /usr/lib/ghc-8.6.4/site-local/random-1.1 . Проблема в том, что теперь он существует в двух местах? Должен ли я удалить один из них?

3. Похоже, это особенность Arch Linux. Я обновил свой ответ.

4. Спасибо! Я не понимал, что Arch имеет отношение к делу, поэтому я даже не упомянул об этом, поэтому я впечатлен, что вы смогли определить проблему, несмотря на мою неполную информацию. Я не мог просить лучшего ответа, и в будущем я буду использовать динамическое связывание.