Программы на Хаскеле компилируются на сервере с помощью GHC 7.6.1. Компилятор запускается со следующими опциями:
ghc -v0 -O %1
Вы можете скачать компилятор на этой странице.
Примеры решения задач
Пример решения задачи 1000. A + B problem на Хаскеле:
main = do
[a, b] <- (map read . words) `fmap` getLine
print (a+b)
Также можно воспользоваться функцией sum:
main = interact $ show . sum . map read . words
Пример решения задачи 1001. Обратный корень на Хаскеле:
main = interact $
unlines . reverse . map (show.sqrt.fromInteger.read) . words
Это решение работает на пределе ограничения по времени. К сожалению, в Хаскеле стандартный тип String крайне неэффективен. Если требуется считать или вывести много чисел, как в этой задаче, придется прибегать к различным ухищрениям.
Во-первых, модуль Data.ByteString.Char8 содержит строковый тип, основанный на массиве, а не на связном списке символов. Во-вторых, теперь мы не можем использовать стандартные функции read и show для ввода/вывода чисел. Если аналог read ещё есть, то show уже нужно писать свой.
import Data.List
import Data.Char
import Data.Maybe
import qualified Data.ByteString.Char8 as B
Для чтения чисел применим функцию readInteger.
readD :: B.ByteString -> Double
readD = fromInteger . fst . fromJust . B.readInteger
Выводить число придется самостоятельно. Обратите внимание, что iPart и fPart имеют тип Integer, тут он быстрее, чем Int64.
showD :: Double -> B.ByteString
showD n = B.pack $ show iPart ++ '.' : fDigs
where
(iPart, fPart) = quotRem (round (10000 * sqrt n)) 10000
fDigs = let s = show fPart
in replicate (4 - length s) '0' ++ s
Вывести числа одним куском не получится из-за ограничения по памяти, так что с каждым числом будем работать отдельно.
main = B.getContents >>=
mapM_ (B.putStrLn.showD) . reverse . map readD . B.words
Новое решение работает более чем в 10 раз быстрее исходной версии.
Массивы
Рекомендуется пользоваться unboxed массивами (UArray из Data.Array.Unboxed и STUArray из Data.Array.ST), так как они в несколько раз быстрее.
Если производительности все еще недостаточно, помогут функции unsafeRead, unsafeWrite и unsafeAt из Data.Array.Base. Они не производят проверок на принадлежность индекса границам массива, а также считают, что массив индексируется от 0.
Map и Set
Если в качестве ключей в Map или Set выступает Int, как это часто бывает, используйте Data.IntMap (Data.IntSet), оптимизированные специально для Int.
Ленивые вычисления
Никакое выражение в Хаскеле не вычисляется, пока оно не понадобится. То есть, можно вывести первый элемент бесконечного списка. Можно возвести 10 в 1000000 степень — и ничего не случится, пока вы не попытаетесь, например, вывести значение на экран.
Проблема кроется в том, что невычисленные значения (thunks) занимают много памяти, а на их вычисление тратится определённое «лишнее» время. Например, строчка
foldl (+) 0 [1..1000]
когда придёт пора её вычислять, сначала развернется в пямяти в
(((...(0 + 1) + 2) + 3) + ... 999) + 1000
что может привести к переполнению стека или неоправданно возросшему времени выполнения.
С ленивостью можно бороться тремя способами:
- Использование функций и структур данных, форсирующих вычисления (обычно помечены словом Strict или одинарной кавычкой —
foldl', Data.Map.Strict, UArray и т.д.) - Связывание значений при помощи
seq. f (a `seq` b) означает, что при вычислении b будет автоматически вычислено и a, даже если оно нигде потом не понадобится. - Восклицание. Например, объявление функции
f !a = ... аналогично f a = a `seq` ....
Некоторые полезные модули
- Data.Complex — комплексные числа.
- Data.Fixed — числа с фиксированным количеством знаков после запятой, а также обобщение
div и mod на действительные числа. - Data.Sequence — списки, поддерживающие быстрое добавление в оба конца, конкатенацию, доступ к произвольному элементу.
- Text.Printf — копия
printf из языка C. - Text.ParserCombinators.ReadP — удобное написание парсеров для сложных грамматик (но и для арифметических выражений подойдет).
- GHC.Exts — определяет
groupWith и sortWith. Отсортировать строки в порядке возрастания длины теперь можно так: sortWith length strings.