2015-10-21 2 views
14

У меня есть функция (*~). Большая часть стоимости оценки 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

Я не уверен, что частичная оценка вас купила. 'y'' уже будет использоваться. Вы хотите заметок? Вам нужно будет добавить memoization самостоятельно. Какое правило вы бы хотели написать? –

+1

Что произойдет, если вы используете пользовательский 'flip'? 'flip 'f x = \ y -> inline f y x' – dfeuer

+2

@ReinHenrichs Будет ли' '' уже использоваться? Если так, то мое понимание довольно сломанно, и я хотел бы принять ответ, объясняющий, как это сделать. Если я делаю 'fmap (* ~ y) someLongList', он не будет пересматриваться каждый раз? –

ответ

5

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

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

+1

Это хороший момент и решит проблему. Но тип результата «дорогой» в настоящее время является скрытой деталью реализации, потому что он действительно не представляет интереса для пользователей библиотеки, которая предоставляет '(* ~)'. –

+2

На самом деле, это не было бы скрытой реализацией в вашем случае, вы просто разоблачили бы его по-другому. Вы также будете запутывать свое намерение и скрывать это от системы типов, и, следовательно, вам придется иначе информировать пользователя о том, как ваша специальная функция должна использоваться. Это не могло бы быть хорошим с точки зрения удобства использования. И, опять же, это пошло бы против разделения проблем. У вас есть список признаков того, что ваш подход уже некорректен, поэтому лучше подумайте дважды. –

+0

Хорошие баллы. –

Смежные вопросы