У меня проблемы с получением GHC, чтобы специализировать функцию с ограничением класса. У меня есть минимальный пример моей проблемы здесь: Foo.hs и Main.hs . Два файла компилируются (GHC 7.6.2, ghc -O3 Main) и запускаются.
ПРИМЕЧАНИЕ:
Foo.hs действительно урезано. Если вы хотите понять, зачем нужно ограничение, вы можете увидеть немного больше кода здесь . Если я помещу код в один файл или внесу множество других незначительных изменений, GHC просто вставит вызов plusFastCyc. Этого не произойдет в реальном коде, потому что plusFastCycон слишком большой для встроенного GHC, даже если он помечен INLINE. Дело в том, чтобы специализировать вызов plusFastCyc, а не встроить его. plusFastCycво многих местах реального кода вызывается, поэтому дублирование такой большой функции нежелательно, даже если бы я мог заставить GHC сделать это.
Код представляет интерес plusFastCycв Foo.hs, воспроизведен здесь:
{-# INLINEABLE plusFastCyc #-}
{-# SPECIALIZE plusFastCyc ::
forall m . (Factored m Int) =>
(FastCyc (VT U.Vector m) Int) ->
(FastCyc (VT U.Vector m) Int) ->
(FastCyc (VT U.Vector m) Int) #-}
-- Although the next specialization makes `fcTest` fast,
-- it isn't useful to me in my real program because the phantom type M is reified
-- {-# SPECIALIZE plusFastCyc ::
-- FastCyc (VT U.Vector M) Int ->
-- FastCyc (VT U.Vector M) Int ->
-- FastCyc (VT U.Vector M) Int #-}
plusFastCyc :: (Num (t r)) => (FastCyc t r) -> (FastCyc t r) -> (FastCyc t r)
plusFastCyc (PowBasis v1) (PowBasis v2) = PowBasis $ v1 + v2
Main.hsФайл имеет два драйвера: vtTest, которая проходит в ~ 3 секунды, и fcTest, которая проходит в ~ 83 секунд при компиляции с -O3 использования forall«d специализации.
В ядре показывает , что для vtTestтеста, код прибавления специализируясь на Unboxedвекторы над Intс, и т.д., в то время как общий вектором код используется для fcTest. В строке 10, вы можете увидеть , что GHC ли написать специализированную версию plusFastCyc, по сравнению с общей версией на линии 167. Правило для специализации по линии 225. Я считаю , это правило должно стрелять по линии 270. ( main6звонки iterate main8 y, так main8это где plusFastCycдолжно быть специализировано.)
Моя цель - сделать fcTestтак же быстро, как и vtTestпо специализации plusFastCyc. Я нашел два способа сделать это:
- Звоните по простоте
inlineизGHC.ExtsвfcTest. - Удалить
Factored m Intограничение наplusFastCyc.
Вариант 1 является неудовлетворительным, потому что в реальной базе кода plusFastCycчасто используется операция и очень большая функция, поэтому ее не следует вставлять при каждом использовании. Скорее GHC следует назвать специализированной версией plusFastCyc. Вариант 2 на самом деле не вариант, потому что мне нужно ограничение в реальном коде.
Я пробовал различные варианты использования (и не использовать) INLINE, INLINABLEи SPECIALIZE, но ничего не похоже на работу. ( РЕДАКТИРОВАТЬ : я, возможно, лишился слишком много, plusFastCycчтобы сделать мой пример маленьким, поэтому я INLINEмог бы сделать функцию встроенной. Это не происходит в моем реальном коде, потому что plusFastCycон такой большой.) получать любые match_co: needs more casesили RULE: LHS too complicated to desugar(и здесь ) предупреждения, хотя я получал много match_coпредупреждений, прежде чем свернуть пример. Предположительно, «проблема» является Factored m Intограничением в правиле; если я внесу изменения в это ограничение, будет fcTestработать так же быстро, как и vtTest.
Я делаю что-то, что GHC просто не нравится? Почему GHC не специализируется plusFastCyc, и как я могу это сделать?
ОБНОВИТЬ
Проблема сохраняется в GHC 7.8.2, поэтому этот вопрос по-прежнему актуален.
m, а именноM. Это сделало свою работу, но я не могу специализироваться на конкретных фантомных типах в реальной программе, поскольку они ограничены.