Основная причина, по которой Applicative []
имеет поведение генерации всех возможных комбинаций, а не какое-либо поведение zippy, заключается в том, что Applicative
является суперклассом Monad
и предназначен для поведения в соответствии сMonad
экземпляр, когда он существует.Monad []
обрабатывает списки как неудачный и приоритетный выбор, как и экземпляр Applicative []
.Люди часто проводят рефакторинг монадического кода, используя аппликативный интерфейс, чтобы уменьшить количество промежуточных имен, необходимых для значений, и увеличить возможности параллелизма.Было бы довольно страшно, если бы это вызвало значительный сдвиг в функциональной семантике.
Кроме того, правда в том, что вы избалованы выбором для Applicative []
экземпляров, и даже более того, если вы считаете пустым /непустые и конечные / коиндуктивные / бесконечные вариации.Почему это так?
Ну, как я уже говорил в в этом ответе , каждый Applicative f
начинает свою жизнь как Monoid (f ())
, объединяя формы данныхпрежде чем мы начнем беспокоиться о значениях .Списки являются показательным примером.
[()]
в основном тип чисел.Числа во многих отношениях являются моноидами.
Взятие Applicative []
из Monad []
равносильно выбору моноида, генерируемого 1
и *
.
Между тем, Applicative ZipList
эксплуатирует Haskell'sкоиндуктивное слияние и сводится к выбору моноида, порожденного бесконечностью и минимумом.
Вопрос предлагает случай, который не является законным, но близок к тому, который есть.Вы заметите, что <*>
не определено для пустого списка функций, но для непустых списков функций, оно дополняет список аргументов.Асимметрично он усекается, когда заканчиваются аргументы.Что-то не совсем правильно.
Далее следуют два возможных варианта исправления.
Один из них - обрезать пустое с обеих сторон, а затем вы должны взять pure = repeat
и у вас будет ZipList
.
Другое - исключить пустые списки и блокнот с обеих сторон.Затем вы получаете Applicative
, сгенерированное из Monoid
на положительных чисел, сгенерированных 1 и максимумом .Так что это не ZipList
вообще.Это то, что я назвал PadMe
в этом ответе .Причина, по которой вам нужно исключить 0, заключается в том, что для каждой позиции в выходных данных <*>
вам нужно указывать на позицию в обоих входах, откуда берутся функция и ее аргументы (соответственно).Вы не можете набивать, если вам нечего набивать.
Это забавная игра.Выберите Monoid
для чисел и посмотрите, сможете ли вы превратить его в Applicative
для списков!