Вызов функции в Haskell - проблема начинающего

Только что начал изучать Haskell.

У меня есть пустой исходный файл с этим внутри:

pe :: (Integral a) => a -> a
pe y = sum [x | x <- [1..y-1], x `mod` 3 == 0 || x `mod` 5 == 0]

Теперь, если я ghci это, я могу вызвать pe так:

*Main> pe 1000
233168

Как мне его вызвать из исходного файла? Если у меня есть

pe 1000

он возвращает загадочную ошибку:

GHC stage restriction: `pe'
   is used in a top-level splice or annotation,
   and must be imported, not defined locally
 In the expression: pe 1000

Нужно ли объявлять его в основном или что-то в этом роде?

Ответ 1

Да, вам нужно подключить его к вашей функции main. Например,

main = print (pe 1000)

Если вы хотите иметь несколько вызовов, вы можете комбинировать их с do -notation:

main = do
    print (pe 500)
    print (pe 1000)

Ответ 2

Исходный файл Haskell содержит последовательность определений, а не выражений. Таким образом, вы не можете просто выразить выражение на верхнем уровне файла, вы должны поместить его в тело определения. Так как pe 1000 не является определением, вы получаете сообщение об ошибке.

Но почему такое загадочное сообщение об ошибке? GHC имеет расширение под названием Template Haskell, которое позволяет вам программно создавать определения во время компиляции. Чтобы достичь этого, вы можете помещать выражение в место, где обычно допускаются только определения и оценивает выражение во время компиляции и заменяет выражение его результатом (который должен быть определением) - это называется сплайсированием, и тогда выражение называется сращиванием. Такое сращивание должно отвечать двум требованиям:

  • Любые идентификаторы, используемые в выражении, должны быть определены в другом исходном файле (это необходимо для того, чтобы используемые функции уже скомпилировались, когда выражение встречается и, следовательно, может быть вызвано во время компиляции)
  • Тип выражения должен быть типом шаблона Haskell, который представляет действительное определение.

Итак, поскольку ваше выражение pe 1000 появляется где-то, где допускаются только определения, GHC предполагает, что это сплайсинг. Однако, поскольку он не соответствует первому из вышеуказанных критериев, то есть он определяется в текущем файле вместо другого файла, GHC жалуется на это. Конечно, это не соответствует второму условию, но GHC еще не добрался до этого, когда он выдает сообщение об ошибке. Если pe были определены в другом исходном файле, вы получили сообщение об ошибке, жалующееся на то, что pe имеет неправильный тип.