C # , Scala, Haskell, Lisp и Python ведут себя одинаково zip
: если одна коллекция длиннее, хвост молча игнорируется.
Это может быть и исключение, но я не слышал ни о каком языке, использующем этот подход.
Это озадачивает меня. Кто-нибудь знает причину, почему так zip
задумано? Я предполагаю, что для новых языков это сделано, потому что другие языки делают это таким образом. Но какова была основная причина?
Я задаю здесь фактический, исторический вопрос, а не о том, нравится ли это кому-то или это хороший или плохой подход.
Обновление : если бы меня спросили, что делать, я бы сказал - сгенерировать исключение, почти так же, как индексирование массива (несмотря на то, что «старые» языки делали все возможное, как обрабатывать индекс за пределами границ, UB, расширять массив, и т.д).
источник
zipWithIndex
предоставляя генератор натуральных чисел Теперь, только недостающая часть информации - то , что было его причиной? :-) (кстати. Пожалуйста, перепостите свой комментарий как ответ, спасибо).Ответы:
Это почти всегда то, что вы хотите, и когда это не так, вы можете сделать заполнение самостоятельно.
Основная проблема заключается в ленивой семантике, когда вы не знаете длину при первом запуске
zip
, поэтому вы не можете просто выбросить исключение в начале. Вам нужно будет сначала вернуть все общие элементы, а затем сгенерировать исключение, которое не будет очень полезным.Это также вопрос стиля. Императивные программисты привыкли вручную проверять граничные условия повсюду. Функциональные программисты предпочитают конструкции, которые не могут потерпеть неудачу в дизайне Исключения крайне редки. Если у функции есть способ вернуть разумное значение по умолчанию, функциональные программисты примут его. Композиционность - король.
источник
zip
в настоящее время реализовано. Исключением броска является просто изменение «стоп-доходности» на «бросок». Третий абзац - возврат пустого элемента для выхода за границы не может завершиться неудачей, но все же я сомневаюсь, что любой разработчик FP проголосовал бы за это, это хороший дизайн.zip
объединяете две бесконечные последовательности, вы не знаете размера в начале. На третий абзац я сказал разумный дефолт. Возвращение пустым в этом случае не было бы разумно, тогда как отбрасывание хвоста очевидно.Потому что нет очевидного способа завершить хвост. Любой выбор того, как это сделать, приведет к неочевидному хвосту.
Хитрость заключается в том, чтобы явно удлинить ваш самый короткий список, чтобы он соответствовал длине самого длинного с ожидаемыми значениями.
Если zip сделал это для вас, вы не могли бы знать, какие значения он заполнял интуитивно. Был ли цикл в списке? Это повторило бесполезное значение? Какое среднее значение для вашего типа?
Нет никакого смысла в том, что делает zip, который можно использовать, чтобы интуитивно понять, как удлинится хвост, поэтому единственное разумное, что нужно сделать, это работать с доступными значениями, а не придумывать что-то, чего ваш потребитель может не ожидать.
Также помните, что вы имеете в виду очень конкретную известную функцию с определенной известной семантикой. Но это не значит, что вы не можете сделать похожую, но немного другую функцию . Тот факт
x
, что есть общая функция , не означает, что вы не можете решить, для какой цели,x
и с какой целью вы хотитеy
.Хотя помните, что эта и многие другие общие функции стиля FP являются общими, потому что они просты и обобщены, так что вы можете настроить свой код, чтобы использовать их и получить желаемое поведение. Например, в C # вы могли бы просто
Или другие простые вещи. Подходы FP делают модификации настолько простыми, потому что вы можете повторно использовать части, а также иметь реализации настолько маленькими, как указано выше, что создание ваших собственных модифицированных версий вещей чрезвычайно просто.
источник
zip
мог бы заполнить нулями, что часто является интуитивно понятным решением. Рассмотрим типzip :: [a] -> [b] -> [(Maybe a, Maybe b)]
. Конечно, тип результата немного ^ H ^ H, довольно непрактичный, но он позволил бы легко реализовать любое другое поведение (сокращение, исключение) поверх него.mempty
, у объектов есть нуль, чтобы заполнить пространство, но вы хотите, чтобы он придумал такую вещь для int и других типов? Конечно, C # имеет,default(T)
но не все языки, и даже для C # это действительно очевидное поведение? Я так не думаю