Как компилятор Haskell обрабатывает оператор 'where'?

StackOverflow https://stackoverflow.com/questions/3581381

Вопрос

В следующей функции мне интересно, достаточно ли умен компилятор, чтобы решить это x будет ли он оставаться постоянным или будет вычислять начало списка для каждого элемента в списке?(Я использую GHC)

allSame :: Eq a => [a] -> Bool 
allSame xs = all (==x) xs  where x = head xs
Это было полезно?

Решение

Семантика 'where' в GHC заключается в том, что для 'x' будет выделено одно замыкание и оно будет общим для всех применений.Будет сгенерировано новое замыкание для функции (== 'x'), и оптимизатор выведет его, так что оно генерируется только один раз за обход.

Чтобы точно увидеть, какой код генерируется, проверьте Ядро (напримерчерез ghc-ядро).GHC оптимизирует код, чтобы:

M.allSame a eq xs =
    all
      (let 
         ds =
           case xs of 
             []   -> error "bad head"
             x : _-> x
            in
          \y -> x == y
         ) xs

Если вас беспокоит производительность, рассмотрите возможность использования векторов, так как отдельные обходы будут сливаться, устраняя рекурсию.

Другие советы

Я думаю, что Haskell просто оценивает то, что нужно: так ищет x и находит это в where-пункт. Тогда я думаю, что это вычисляет x один раз и делает all.

Если вы хотите проверить его, вы можете написать функцию myall это делает рекурсию в all (==x), но по сути просто печатает сравнительный элемент. Поэтому вы увидите, если вы получите новый аргумент каждый раз или если он останется только тем же одновременно каждый раз.

Редактировать:

Вот небольшая функция, чтобы проверить это: myall Просто собирает первые аргументы и ставит его в список.

myall x [] = [x]
myall x xs =  x:(myall x (tail xs))

test xs = myall (x) xs where x = head xs

Если вы звоните test [1,2,3], вы увидите, что результат [1,1,1,1], т.е. во-первых x оценивается в 1, после этого myall оценивается.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top