Оптимизация частичных вычислений в Haskell

I' Мне любопытно, как оптимизировать этот код:

fun n = (sum l, f $ f0 l, g $ g0 l)
  where l = map h [1..n]

Предполагая, что f, f0, g, g0и hвсе дорого, но создание и хранение lчрезвычайно дорого.

Как написано, lсохраняется до тех пор, пока возвращаемый кортеж не будет полностью оценен или не будет собран мусор. Вместо этого length l, f0 lи g0 lдолжны выполняться всякий раз, когда выполняется любой из них, но fи gдолжны быть отложены.

Похоже, это поведение можно исправить, написав:

fun n = a `seq` b `seq` c `seq` (a, f b, g c)
  where
    l = map h [1..n]
    a = sum l
    b = inline f0 $ l
    c = inline g0 $ l

Или очень похожее:

fun n = (a,b,c) `deepSeq` (a, f b, g c)
  where...

Возможно, мы могли бы указать кучу внутренних типов для достижения тех же эффектов, что выглядит болезненно. Есть ли другие варианты?

Кроме того, я, очевидно, надеюсь, что с моими inlineкомпилятор объединяет sum, f0и g0в один цикл, который создает и использует lпочленно. Я мог бы сделать это явным с помощью ручного встраивания, но это было бы отстойно. Существуют ли способы явного предотвращения создания списка lи/или принудительного встраивания? Возможно, прагмы, которые выдают предупреждения или ошибки, если встраивание или слияние не удается во время компиляции?

Кстати, мне любопытно, почему seq, inline, lazyи т. д.все определены в let x = x in xв Прелюдии. Это просто для того, чтобы дать им определение для переопределения компилятором?

8
задан Jeff Burdges 22 April 2012 в 09:54
поделиться