Как и в заголовке: какие гарантии существуют для функции, возвращающей единицу функции Haskell, которая будет оценена? Можно было бы подумать, что в таком случае нет необходимости выполнять какую-либо оценку, компилятор может заменить все такие вызовы непосредственным ()
значением, если нет явных запросов на строгость, и в этом случае код может решить, должен ли он возврат ()
или снизу.
Я экспериментировал с этим в GHCi, и кажется, что происходит обратное, то есть такая функция, кажется, оценивается. Очень примитивным примером будет
f :: a -> ()
f _ = undefined
Оценка f 1
выдает ошибку из-за наличия undefined
, поэтому определенная оценка обязательно произойдет. Однако не ясно, насколько глубока оценка; иногда кажется, что все идет так глубоко, как необходимо для оценки всех обращений к функциям, которые возвращаются ()
. Пример:
g :: [a] -> ()
g [] = ()
g (_:xs) = g xs
Этот код зацикливается бесконечно, если представлен с g (let x = 1:x in x)
. Но потом
f :: a -> ()
f _ = undefined
h :: a -> ()
h _ = ()
может использоваться, чтобы показать, что h (f 1)
возвращается ()
, поэтому в этом случае не все подвыражения с единичными значениями оцениваются. Какое общее правило здесь?
ЭТА: конечно, я знаю о лени. Я спрашиваю, что мешает авторам компиляторов сделать этот конкретный случай еще более ленивым, чем обычно возможно.
ETA2: краткое изложение примеров: GHC выглядит ()
точно так же, как и любой другой тип, т. Е. Как если бы возник вопрос о том, какое регулярное значение, населяющее тип, должно быть возвращено из функции. Тот факт, что есть только одно такое значение, кажется, (ab) не используется алгоритмами оптимизации.
ETA3: когда я говорю «Haskell», я имею в виду «Haskell как определено отчетом», а не «Haskell-H-in-GHC». Кажется, это предположение не разделяется так широко, как я себе представлял (это было «на 100% читателей»), иначе я, вероятно, смог бы сформулировать более четкий вопрос. Тем не менее, я сожалею об изменении названия вопроса, так как он изначально спрашивал, какие есть гарантии для вызова такой функции.
ETA4: может показаться, что этот вопрос прошел, и я считаю его без ответа. (Я искал функцию «закрыть вопрос», но нашел только «ответить на свой вопрос», и, поскольку на него нельзя ответить, я не пошел по этому пути.) Никто не поднял из Отчета ничего, что могло бы решить его в любом случае. который я склонен истолковывать как сильный, но не определенный ответ «нет гарантии для языка как такового». Все, что мы знаем, это то, что текущая реализация GHC не пропустит оценку такой функции.
Я столкнулся с реальной проблемой при портировании приложения OCaml на Haskell. Исходное приложение имело взаимно рекурсивную структуру многих типов, и код объявлял ряд функций, вызванных assert_structureN_is_correct
для N в 1..6 или 7, каждая из которых возвращала единицу, если структура действительно была правильной, и выдает исключение, если это не так. , Кроме того, эти функции вызывали друг друга, поскольку они разлагали условия корректности. В Haskell это лучше обрабатывается с помощью Either String
монады, поэтому я расшифровал ее таким образом, но вопрос как теоретический вопрос остался. Спасибо за все вклады и ответы.
f 1
«заменяется» на undefined
во всех случаях.
... -> ()
может 1) завершаться и возвращаться ()
, 2) завершаться с ошибкой исключения / времени выполнения и ничего не возвращать, или 3) расходиться (бесконечная рекурсия). GHC не оптимизирует код, предполагая, что только 1) может произойти: если f 1
требуется, он не пропускает свою оценку и возврат ()
. Семантика Haskell - оценить ее и посмотреть, что происходит среди 1,2,3.
()
этом вопросе нет ничего особенного (типа или значения). Все те же наблюдения произойдут, если заменить их () :: ()
, скажем, 0 :: Int
везде. Это все просто скучные старые последствия ленивой оценки.
()
типа, ()
и undefined
.
h1::()->() ; h1 () = ()
иh2::()->() ; h2 _ = ()
. Запустите обаh1 (f 1)
иh2 (f 1)
, и увидите, что требует только первый(f 1)
.