Почему доступ к System.Info не считается операцией ввода-вывода в Haskell?

25

В модуле System.Infoя вижу эти функции:

os :: String
arch :: String
compilerName :: String
compilerVersion :: Version

Почему там нет IO? Они получают доступ к системе ... Я ошибаюсь? Мое ожидание было что-то вроде:

os :: IO String
arch :: IO String
compilerName :: IO String
compilerVersion :: IO Version

Случай использования:

      print os            -- "darwin"
      print arch          -- "x86_64"
      print compilerName  -- "ghc"
Франсиско Альберт
источник

Ответы:

29

Вы не получаете эту информацию во время выполнения . Они жестко запрограммированы в компиляторе, установленном в вашей системе.

Это наиболее очевидно, если вы посмотрите на определение, которое можно compilerNameнайти в http://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html .

compilerName :: String
compilerName = "ghc"

но даже что-то вроде os

os :: String
os = HOST_OS

определяется в терминах иначе неопределенного имени HOST_OS(значение, начинающееся с заглавной буквы ??), которое предполагает, что это просто заполнитель, который заменяется во время установки.

Кто-то также может исправить меня (пожалуйста!), Но {-# LANGUAGE CPP #-}прагма в верхней части этого файла предполагает, что HOST_OSпрепроцессор C перед компиляцией заменяет соответствующие строки на соответствующие строки.

chepner
источник
2
Если ОП действительно хочет, чтобы IOтам было что-то, есть обертка вокруг uname(3)Hackage: hackage.haskell.org/package/bindings-uname
thsutton
19

Вопрос хороший. Ответ, как бы то ни было, заключается в том, что эти значения являются статическими для каждой программы компиляции. Они по сути компилируются в программу и после этого никогда не меняются. Таким образом, ничто (в допущениях, используемых GHC) не нарушается, если вы рассматриваете их как константы. И удобнее использовать простую константу, чем действие ввода-вывода.

Но это все виды устаревших рассуждений. Хаскель это старый язык. (Нет, на несколько лет он старше, чем Java.) Было создано много библиотек, основанных на рассуждениях, которые больше не считаются лучшими практиками. Это примеры этого. Современная библиотека, разоблачающая их, вероятно, сделает их действиями ввода-вывода, даже если результаты не изменятся после компиляции. Более полезно помещать вещи, которые не являются константами на уровне источника, за действиями ввода-вывода, хотя есть все еще некоторые заметные исключения, такие как Intизменение размера между 32- и 64-битными платформами.

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

деревенщина
источник
-9

РЕДАКТИРОВАТЬ: Спасибо @interjay и @Antal Spector-Zabusky за объяснение, почему этот ответ опровергается. Они написали

Документация немного вводит в заблуждение. Значения жестко запрограммированы в компиляторе GHC. Через 48 лет вы наверняка знаете, что реальный код всегда превосходит документацию. - interjayчера @ andy256 Вы абсолютно правы в том, что документация плохая (действительно, именно поэтому Франциско задал этот вопрос в первую очередь), и ваше замешательство понятно. Особенность Haskell в том, что если эти значения String могут изменяться во время выполнения, это будет вопиющей ошибкой - переменные не могут изменяться. В этом значение конструктора типа IO - он представляет вычисление, которому разрешен доступ к «внешнему миру», и, следовательно, результат, который может измениться. Выполнение системного вызова является хорошим примером действия ввода-вывода. … [1/2] - Antal Spector-Zabusky 9 часов назад @ andy256… (Еще одним действием ввода-вывода может быть «обновление глобального счетчика».) Поэтому, когда мы видим строку, мы знаем, что она не может установить связь с ОС под капотом. Вот почему, возможно, удивительно, если вы не привыкли к Haskell, было бы нелегко реализовать os :: String для выполнения системного вызова - любое такое значение нереализуемо в базовом Haskell, нарушало бы ожидания каждого программиста о том, как программы работать, и, возможно, даже сбить с толку компилятор и оптимизатор (не теоретическая проблема - есть ответы на переполнение стека, где люди сталкиваются с аналогичными проблемами). [2/2] - Антал Спектор-Забуский Вот почему, возможно, удивительно, если вы не привыкли к Haskell, было бы нелегко реализовать os :: String для выполнения системного вызова - любое такое значение нереализуемо в базовом Haskell, нарушало бы ожидания каждого программиста о том, как программы работать, и, возможно, даже сбить с толку компилятор и оптимизатор (не теоретическая проблема - есть ответы на переполнение стека, где люди сталкиваются с аналогичными проблемами). [2/2] - Антал Спектор-Забуский Вот почему, возможно, удивительно, если вы не привыкли к Haskell, было бы нелегко реализовать os :: String для выполнения системного вызова - любое такое значение нереализуемо в базовом Haskell, нарушало бы ожидания каждого программиста о том, как программы работать, и, возможно, даже сбить с толку компилятор и оптимизатор (не теоретическая проблема - есть ответы на переполнение стека, где люди сталкиваются с аналогичными проблемами). [2/2] - Антал Спектор-Забуский и потенциально даже сбить с толку компилятор и оптимизатор (не теоретическая проблема - есть ответы о переполнении стека, где люди сталкиваются с аналогичными проблемами). [2/2] - Антал Спектор-Забуский и потенциально даже сбить с толку компилятор и оптимизатор (не теоретическая проблема - есть ответы о переполнении стека, где люди сталкиваются с аналогичными проблемами). [2/2] - Антал Спектор-Забуский

В настоящее время он имеет два голоса для удаления. Я позволю этому процессу идти своим чередом, но предполагаю, что он действительно имеет определенную ценность. С другой стороны, их объяснения показывают, что вопрос был слабым, как и ответы, так как новичок из Хаскелла мог легко следовать рассуждениям, которые я сделал.

Оригинальный ответ:

Я не программист на Haskell, но оба ответа уже не соответствуют документации, которую связал OP.

Моя интерпретация документации следующая.

os :: String - Это дает вам «Операционная система, в которой работает программа».

Я ожидаю, что это выдаст системный вызов для получения информации. Поскольку система, в которой скомпилирована программа, может отличаться от той, в которой она выполняется, она не может быть значением, вставленным компилятором. Если код интерпретируется, то интерпретатор может предоставить результат, который должен быть получен с помощью системного вызова.

arch :: String - Это дает вам «Архитектуру машины, на которой работает программа».

Опять же, я ожидаю, что это вызовет системный вызов для получения информации. Поскольку система, в которой скомпилирована программа, может отличаться от той, в которой она выполняется, она не может быть значением, вставленным компилятором.

compilerName :: String - Это дает вам «реализацию на Haskell, с помощью которой программа была скомпилирована или интерпретируется».

Это значение, безусловно, вставляется компилятором / интерпретатором.

compilerVersion :: String- Это дает вам «версию, compilerNameс которой программа была скомпилирована или интерпретируется».

Это значение, безусловно, вставляется компилятором / интерпретатором.

Хотя вы можете считать, что первые два вызова получают входные данные, результат получается из значений, хранящихся в операционной системе. Обычно ввод-вывод относится к доступу к вторичной памяти.

andy256
источник
3
Это не верно для Haskell. Здесь любые вычисления неупорядочены и их результат может быть кэширован. Функции чистые, поэтому, если функция не принимает аргументов, она очень похожа на константу. Функции одного аргумента выглядят как хеш-карты или словари, которые вычисляют значение на основе ключа. Вы не можете использовать внешнюю среду, выполнять системные вызовы в таких функциях, вы даже не можете получить случайное число или текущую дату. Но если вы действительно хотите использовать эту «последовательность» или среду, то вам нужно использовать IOмонаду, чтобы эмулировать состояние, эмулировать последовательность операций
Юрий Коваленко
«Вы не можете использовать внешнюю среду, делать системные вызовы в таких функциях» - конечно, вы можете, особенно если «вы» - компилятор Haskell! Для реализации на Haskell было бы очень просто реализовать os :: Stringсистемный вызов при оценке.
Таннер Светт
2
Я не думаю, что вы понимаете значение монады IO в Haskell.
Sneftel
@Sneftel Вы, конечно, правы. Я решил ответить, потому что после 48 лет программирования в каждой парадигме и написания нечетного компилятора первоначальные ответы не соответствовали документации, и они до сих пор не соответствуют. Это ясно говорит об этом osи archполучается во время выполнения.
andy256
1
Документация немного вводит в заблуждение. Значения жестко запрограммированы в компиляторе GHC. Через 48 лет вы наверняка знаете, что реальный код всегда превосходит документацию.
междурядный