Я не очень хорошо знаком с тем, что Haskell/GHC может оптимизировать код. Ниже у меня есть довольно "грубая сила" (в декларативном смысле) реализация проблемы n queens. Я знаю, что его можно написать более эффективно, но это не мой вопрос. Это заставило меня задуматься о возможностях и ограничениях GHC.
Я выразил это в том, что я считаю довольно простым декларативным смыслом. Фильтрующие перестановки [1..n], которые соответствуют предикату For all indices i,j s.t j<i, abs(vi - vj) != j-i
Я бы надеялся, что это то, что может быть оптимизировано, но это также похоже на то, чтобы просить много компилятора.
validQueens x = and [abs (x!!i - x!!j) /= j-i | i<-[0..length x - 2], j<-[i+1..length x - 1]]
queens n = filter validQueens (permutations [1..n])
oneThru x = [1..x]
pointlessQueens = filter validQueens . permutations . oneThru
main = do
n <- getLine
print $ pointlessQueens $ (read :: String -> Int) n
Это работает довольно медленно и быстро растет. n=10
занимает около секунды, а n=12
- навсегда. Без оптимизации я могу сказать, что рост является факториалом (# перестановок), умноженным на квадратичное (# различий в предикате для проверки). Есть ли способ, которым этот код может работать лучше, чем интеллектуальная компиляция? Я пробовал основные ghc
опции, такие как -O2
и не заметил существенной разницы, но я не знаю более тонких точек (просто добавил flagS)
Мое впечатление, что функция я call queens
не может быть оптимизирована и должна генерировать все перестановки перед фильтром. У бесплатной версии есть больше шансов? С одной стороны, я чувствую, что умное понимание функций между фильтром и предикатом может сбить некоторые явно нежелательные элементы, прежде чем они будут полностью сгенерированы, но, с другой стороны, это похоже на то, что нужно много спросить.
Извините, если это кажется бессвязным, я думаю, мой вопрос
- Возможно ли более оптимизированная версия вышеописанной функции оптимизировать?
- Какие шаги я могу предпринять для создания/компиляции/времени ссылки для оптимизации оптимизации?
- Можете ли вы вкратце описать возможные (и противопоставить невозможным!) средствам оптимизации для вышеуказанного кода? В какой момент процесс происходит?
- Есть ли какая-то конкретная часть вывода
ghc --make queensN -O2 -v
, на которую я должен обратить внимание? Мне ничего не стоит. Даже не вижу большой разницы в выходе из-за флагов оптимизации.
Я не слишком озабочен этим примером кода, но я думал, что это заставляет меня думать, и мне кажется, что это достойный автомобиль для обсуждения оптимизации.
PS - permutations
находится из Data.List и выглядит следующим образом:
permutations :: [a] -> [[a]]
permutations xs0 = xs0 : perms xs0 []
where
perms [] _ = []
perms (t:ts) is = foldr interleave (perms ts (t:is)) (permutations is)
where interleave xs r = let (_,zs) = interleave' id xs r in zs
interleave' _ [] r = (ts, r)
interleave' f (y:ys) r = let (us,zs) = interleave' (f . (y:)) ys r
in (y:us, f (t:y:us) : zs)