Ответ 1
Идея состоит в том, что значение алгебраического типа данных в Haskell имеет вид
C x_1 x_2 ... x_n
где C
- конструктор, а x_i
- аргументы. Что
gfoldl app con
заключается в том, чтобы превратить такое значение в
con C `app` x_1 `app` x_2 ... `app` x_n
превратив тем самым a
в c a
. Предположим, что тип C
есть
C :: T_1 -> T_2 -> ... -> T_n -> D
то рассмотрим типы промежуточных выражений:
con C :: c (T_1 -> T_2 -> ... -> T_n -> D)
con C `app` x_1 :: c (T_2 -> ... -> T_n -> D)
con C `app` x_1 `app` x_2 :: c (... -> T_n -> D)
con C `app` x_1 `app` x_2 ... `app` x_n :: c D
Параметризация над C
позволяет всем этим промежуточным типам
другой. Если бы мы использовали простое сгиб, например gfoldl'
, тогда все
эти промежуточные типы должны быть одинаковыми.
Мотивация для gfoldl
должна быть
единственное обобщение, которое позволяет вам выражать функции SYB gmapQ
и gmapT
(и несколько других). Типы gmapQ
и gmapT
:
gmapQ :: Data a => (forall d. Data d => d -> u) -> a -> [u]
gmapT :: Data a => (forall b. Data b => b -> b) -> a -> a
Пока gmapQ
сворачивает a
в единый список u
и может
выражаться с помощью gfoldl'
, это было бы невозможно для gmapT
.
Однако, используя gfoldl
, мы можем использовать c = Identity
, чтобы мы могли получить
что-то вроде gmapT
и c = Const
, чтобы получить что-то вроде gmapQ
.
Для более подробной информации вы также можете посмотреть на статью Отменить свой шаблонный перезагруженный, который показывает, что gfoldl
является обычным (пока
более высокого порядка) с типом данных, который называется Spine
в этой статье.
Использование тождественных и постоянных функторов для получения как трансформационных, так и обновление поведения из одного базового представления имеет некоторые сходство с тем, как вы получаете операции с линзами из линз "van Laarhoven".