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
в Прелюдии. Это просто для того, чтобы дать им определение для переопределения компилятором?