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

Почему действия getArgs и getProgName IO?

Я полный новичок, который в настоящее время пытается научиться Haskell с помощью Узнать вас о Haskell для Great Good ". Я дошел до раздел, объясняющий, как работать с аргументами командной строки, и что-то меня раздражает.

Из моего понимания (и определение haskell.org), действия предназначены для инкапсуляции побочных эффектов. Аргументы командной строки являются неизменяемыми входами для данного экземпляра программы, тогда в чем смысл getProgName :: IO String, а не getProgName :: String? Иными словами, какой смысл запретить чистую функцию вызывать getProgName?

Обновление

У меня были некоторые отличные ответы на этот вопрос. Я принимаю Дон Стюарт как самый простой и лаконичный, но Конал (с его ассоциированным сообщение в блоге), безусловно, стоит прочитать.

4b9b3361

Ответ 1

Во-первых, getArgs может меняться во время выполнения. См. withArgs.

Во-вторых, getArgs и getProgName попадают в интересный класс нечистых вычислений - они считаются константами во время прогона программы, однако они не являются значениями, доступными во время компиляции, и они меняются от одного программа запускается в другую. У них нет четкого обозначения.

См. ранее обсуждения, где обсуждаются getArgs и вычисления с плавающей запятой. И даже minBound/maxBound может считаться в этом классе.

Ответ 2

Чтобы ответить на такие вопросы, вам понадобится фундамент: что означает, что выражение e имеет тип t? Вы можете дать произвольные ответы для примитивов типа getProgName, но вам этого не нужно. Вместо этого рассмотрите значения выражений и типов. Скажем, что выражение e имеет тип t, когда значение, обозначенное e (т.е. Значение e как математическое значение), принадлежит коллекции, обозначенной знаком t.

Теперь рассмотрим t == String. Какой смысл мы хотим иметь String? Опять же, здесь есть много места для выбора. Тем не менее, есть большая заслуга в выборе полезного кандидата с простейшим математическим определением. В Haskell String == [Char], поэтому мы действительно говорим о значениях [] и Char Наиболее убедительные простые кандидаты, о которых я знаю, заключаются в том, что [] обозначает списки (последовательности), а Char обозначает символы, и, следовательно, String обозначает последовательности символов, т.е. "Строки".

С выбором, что String означает строки, теперь мы можем спросить, возможно ли, что getProgName :: String. Если это так, то значение getProgName должно быть последовательностью символов. Тем не менее, нет единственной последовательности символов, которая фиксирует намерение позади getProgName. (Edit: Предположительно, вы хотите, чтобы getProgName выдавал разные строки, когда он отображается в программах с разными именами.) Поэтому мы должны либо выбрать другой тип, например (но не обязательно) IO String, либо выбрать более сложное значение для String. Последний маршрут может показаться на первый взгляд привлекательным, пока вы не рассмотрите глубинные последствия. Чисто функциональное (более точное "денотативное" ) программирование поддерживает практические, строгие рассуждения благодаря использованию простых значений, таких как последовательности, а не сложные значения, такие как функции из какой-либо среды, включая операционную систему, контекст выполнения компьютера.

Для близких замечаний и обсуждений см. сообщение в блоге Понятия о чистоте в Haskell.

Редактирование: я думаю, что Питер Ландин (дед Хаскелла) лучше всего выразил свое определение "денотативного программирования" (или "подлинно функционального программирования" ), которое он рекомендовал в качестве существенной замены неопределенным терминам, таким как "декларативный" и "декларативный", функционального "программирования. Для справки, цитат и кратких комментариев см. этот комментарий в сообщении Является ли Haskell чисто функциональным языком?.

Ответ 3

Мое понимание чистых функций чиста, потому что вы можете рассуждать с ними в "время кода", и компилятор может во время компиляции. Действия ввода-вывода зависят от времени выполнения. getArgs, который дает аргументы программе только тогда, когда она запущена, является, следовательно, действием IO.

Как узнать, что Haskell ставит:

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

Мы не знаем, что коробка с маленькими ногами принесет в кодовое время или время компиляции.