Частичная оценка правых секций оператора

У меня есть функция (*~). Большая часть стоимости оценки x *~ y исходит из проверки второго аргумента, примерно по этим строкам:

(*~) :: a -> b d -> c d a
x *~ y = case y' of
           Bar -> cheapFunction y' x
           Baz -> cheapFunction2 y' x
           Quux -> cheapFunction3 y' x
  where
    y' = expensive y

Есть ли какой-то способ убедить GHC частично оценить разделы оператора, такие как (*~ y)?

Я попробовал переписать его так:

(*~) = flip go
  where
    go y = let y' = expensive y
            in case y' of
                 Bar -> cheapFunction y'
                 Baz -> cheapFunction2 y'
                 Quux -> cheapFunction3 y'

но, похоже, это не помогло. Я думаю, это может быть из-за того, что flip требует всех аргументов, прежде чем он перевернет?

Один из способов - просто перевернуть сам оператор, но он читается гораздо более естественным образом, когда дорогой операнд находится с правой стороны, потому что он совпадает с существующей нотной записью.

Может ли правильно созданная {-# RULE #-} выручить меня здесь? Если да, то что сказать? (Я не знаю, как далеко синтаксис секционирования будет снят, прежде чем правила будут искать совпадения, между прочим.)

Ответы

Ответ 1

Чтобы вызвать такую ​​оптимизацию, вам нужно убедиться, что ваша функция встроена. Поместите прагму {-# INLINE (*~) #-} перед объявлением функции (*~). Я не могу гарантировать, что он решит вашу проблему, но это единственный способ, с которым я обращаюсь к нему. После этого я проверил созданный код ядра с помощью инструмента ghc-core.

Однако ваша проблема на самом деле является лишь признаком неправильной составы кода. Ваша функция выполняет множество несвязанных вещей. expensive y следует просто исключить из него, тогда ваша проблема будет стерта как таковая. I.e, шаблон использования должен быть x *~ expensive y вместо x *~ y.