Понимание сигнатуры типа gfoldl из Data.Data.Data

Data определяет как одну из основных функций gfoldl:

gfoldl
  :: (Data a)
  => (forall d b. Data d => c (d -> b) -> d -> c b) 
  -> (forall g. g -> c g)   
  -> a  
  -> c a

Какова цель c и c (d -> b) в ней? Почему это не просто обычная складка, что-то вроде

gfoldl'
  :: (Data a)
  => (forall d. Data d => r -> d -> r)
  -> r
  -> a  
  -> r

Ответы

Ответ 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".