Почему так редко используют подписи типов в предложениях where?

Помогает ли это компилятору оптимизировать, или это просто лишняя работа по добавлению дополнительных сигнатур типов? Например, часто можно увидеть:

foo :: a -> b
foo x = bar x
      where bar x = undefined

Скорее, чем:

foo :: a -> b
foo x = bar x
      where bar :: a -> b
            bar x = undefined

Если я опускаю сигнатуру верхнего уровня, GHC выдает мне предупреждение, поэтому, если я не получаю предупреждения, я совершенно уверен, что моя программа верна. Но предупреждения не выдаются, если я опускаю подпись в предложении where.

4 ответа

Решение

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

Кажется, довольно часто вводить where изучающим Haskell с примерами этой формы, поэтому они думают, что "нормальный стиль" - это не давать объявления типов для локальных определений. По крайней мере, это был мой опыт изучения Хаскелла. С тех пор я обнаружил, что многие из моих функций достаточно сложны, чтобы where блок становится довольно непостижимым, если я не знаю тип локальных определений, поэтому я пытаюсь ошибиться, чтобы всегда печатать их сейчас; даже если я думаю, что тип очевиден, когда я пишу код, он может быть не так очевиден, когда я читаю его после того, как некоторое время не смотрел на него. Небольшое усилие для моих пальцев почти всегда перевешивается даже одним или двумя случаями, когда мне приходится делать вывод типа в моей голове!

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

Существует класс локальных функций, типы которых не могут быть написаны на Haskell (то есть без использования расширений GHC). Например:

f :: a -> (a, Int)
f h = g 1
  where g n = (h, n)

Это потому, что пока a в f подпись типа полиморфна, если смотреть снаружи fэто не так изнутри f, В g, это просто какой-то неизвестный тип, но не какой-либо тип, и (стандартный) Haskell не может выразить "тот же тип, что и первый аргумент функции, в которой он определен" на своем языке типов.

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

Если тип сложный или не может быть выведен, вы можете добавить тип.

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

Добавление подписи типа может сделать ваш код быстрее. Возьмем для примера следующую программу (Фибоначчи):

result = fib 25 ;
-- fib :: Int -> Int
fib x = if x<2 then 1 else (fib (x-1)) + (fib (x-2))
  • Без аннотации во 2-й строке это занимает 0,010 сек. бежать.
  • С Int -> Int аннотация, занимает 0,002 сек.

Это происходит потому, что если вы ничего не говорите о fib, это будет напечатано как fib :: (Num a, Num a1, Ord a) => a -> a1Это означает, что во время выполнения дополнительные структуры данных ("словари") должны будут передаваться между функциями для представления Num/Ord. классы типов

Другие вопросы по тегам