Теоретически возможно оптимизировать этот код, но это очень и очень сложно, потому что f
и g
могут потреблять различное количество входного списка.Только когда они потребляют одинаковое количество или g
всегда потребляет больше списка, чем f
(или наоборот), будет возможно выполнить оптимизацию.Проблема остановки препятствует тому, чтобы компилятор обнаружил такие условия в сложном коде.
Только в простых случаях, когда и f
, и g
используют foldr
внутренне, например, было бы возможно выполнить тривиальноеоптимизация без дальнейшего самоанализа.
Функция traverse
здесь вам не поможет, потому что нет разумного способа реализации someCombinator
(Как вы хотите преобразовать несколько вызовов a
в один[a]
без серьезных взломов? И тогда вы все равно вернетесь к тому, с чего начали).
Ваш единственный реальный вариант - сделать f
и g
в папках, чтобы они имели подписи f :: a -> b -> b
и g :: a -> c -> c
, что означает, что значения b
и c
могут быть вычислены постепенно.Затем вы можете использовать \ a -> f a *** g a
, чтобы получить папку, которую вы можете использовать в обычном (прямо в этом случае) сгибе.