Pull to refresh

Comments 145

['1', '7', '11'].map(numStr => parseInt(numStr));

На практике этот код не работает как мы хотели до ECMAScript5. Работает такой


['1', '07', '11'].map(numStr => parseInt(numStr, 10));

в «до ECMAScript5» у вас и стрелочная функция будет вызывать Syntax Error. :)

Не будет, если это старая нода и babel.

Из-за «babel» это уже не про ECMAScript5. В ES5 по спецификации нет стрелочных функций. А кейс «старая нода и babel» это уже синтаксис ES6+ с трансляцией в синтаксис ES5 посредством babel.

Без понятия что за придирки. То, что я написал — почти стандартное eslint правило — всегда писать radix. Еще есть старые браузеры. И большая часть сайтов которые написаны на "es6" это "синтаксис ES6+ с трансляцией в синтаксис ES5 посредством babel".

Я не понимаю, а чего заминусили то? Автор сам попал в ошибку, очевидно — надо смотреть определение функции map, она в коллбэк (как и многие другие функции массивов) отдает элемент, индекс и массив, и использовать как в заголовке статьи по умолчанию не правильно.

У автора проблема из пальца высосана, и основана на внимательности или не знании базовой библиотеки.

На счет стрелочных функций, если вы используете parseInt (а это если по простому — deprecated и надо использовать Number.parseInt) то используйте обычное определение функции
Соотвественно

['1', '7', '11'].map(function(val, idx, array){ return parseInt(val)});
В большинстве случаев можно использовать:
['1', '2', '3'].map(Number)
Хорошая подача и интересный материал. Спасибо
Вот оно, тонкое искусство написать несколько килобайт текста с картинками вместо «parseInt принимает два аргумента».
Автор ещё не знал, что map() передаёт несколько аргументов. Таким образом, всю эту Санта-Барбару можно сократить до: RTFM.
Ага, JavaScript настолько странный, что не зная какие аргументы принимает функция можно выстрелить себе в ногу. Кто бы мог подумать. Статья занимательная конечно, но обычно при встрече с любой подобной «странностью» вопрос решается за минуту на MDN.
То что люди не понимают(не знают), то для них странное)

Просто все нормальные языки реализуют map :: [a] -> (a -> b) -> [b], а JS зачем-то решил отличиться. Поэтому и странный.

Наверное чтобы не добавлять еще одну переменную для текущего индекса?
И можно было писать в одну строчку:
['а', 'b', 'c'].map((el, index) => `${el} at index ${index}`)

Пример из жизни когда это полезно (react)
render () {
 return items.map((el, index) => <li element={el} tabindex={index} />)
}
А вам серьёзно ради этого нужно Map'у портить?
render () {
 var index = 0;
 return items.map((el) => `<li element={el} tabindex={index} />`)
}
Это прям так ужасно? Катастрофа? Много вы таким способом строк наэкономили? А если много — то почему web-странички занимают мегабайты?
Не ужасно и не катастрофа, но добавляет проблем, например имя `index` может быть уже занято в этом скоупе, надо будет новое придумывать. Или например, у вас несколько .map'ов — будете делать var index1..indexN? С таким же успехом можно сказать что вместо map написать for — в принципе тоже не катастрофа.
Вместо той mapы, что в JavaScript уж точно лучше написать for — хотя бы иллюзий не будет.

Если необходим индекс, его всегда можно изящно добавить в одну строчку, просто построив список пар с помощью функции zip (не силён в JS, не знаю местных аналогов).


map (\(element, index) -> ...) $ zip elements [0..]

Из простых атомарных частей (map, zip, генераторы) очень легко строить абстракции любой сложности, на какие только воображения хватит. Зачем все возможные варианты пытаться уместить в одной сложной функции – совершенно не понятно.

Зачем все возможные варианты пытаться уместить в одной сложной функции – совершенно не понятно.

Никто не пытается уместить там ВСЕ возможные варианты, просто добавили еще один аргумент, которые в веб программировании довольно часто используется.
В JS .map — это метод списка, который уже загружен в память. Зачем использовать ненужные абстракции, где одна функция покрывает 99% нужд?
devpony khim Cerberuser ребят, до меня только сейчас дошло что вы похоже не в курсе, что в js обычно функции, у которых несколько аргументов, никто просто по имени в .map не передает. Обычно их оборачивают в анонимную функцию, где уже можно передать те аргументы, которые нужны. В большинстве случаев передается как-раз только первый аргумент.
Т.е. никто на самом деле не делает вот так:
list.map(parseInt)

Обычно делают так:
list.map(x => parseInt(x, 10))

Какой разумный человек вообще будет использовать parseInt без второго аргумента, учитывая его не совсем очевидное поведение
Поэтому не люблю подобные статьи в стиле «как выстрелить себе в ногу в js» — они вводят людей в заблуждение. У всех языков есть свои особенности, которые могут казаться не очевидными на первый взгляд, но при работе с языком обретающими смысл.
Получилось в итоге что-то странное. «Чтобы не добавлять еще одну переменную» суют индекс куда не надо, а потом всю жизнь функцию в функцию заворачивать чтоб этот индекс игнорировать. Как это делается в других языках:

Scala

arr.map { case (x) => ...}
arr.zipWithIndex.map { case (x,i) => ...}

Python

map(lambda x: ..., arr)
map(lambda (x,i): ..., enumerate(arr))

Ruby

arr.each { |x|...}
arr.each_with_index { |x,i|...}

Даже в PHP есть какой-то гибрид map с zip, ну и на том спасибо

array_map(function($x) ..., $arr);
array_map(function($x,$i) ..., $arr, array_keys($arr));
Дядя, ты дурак? У тебя во всех примерах внутри map анонимная функция.
Отличие JS в том что туда можно и не анонимную поставить. Т.к. в JS функции «высшего порядка»

Отличие JS в том что туда можно и не анонимную поставить.
Это кто вам сказал? Вот буквально парой комментариев выше нам вроде объясняли что так делать не следует…

Т.к. в JS функции «высшего порядка»
А в других упомятых языках — низшего, да?

Дядя, ты дурак?
Не знаю кто тут дурак — но точно не человек удивляющийся тому, что фичу, которая нормально поддерживается всеми упомянутыми языками кроме JavaScript объявляют преимуществом именно этого языка…
Т.к. в JS функции «высшего порядка»

А в других упомятых языках — низшего, да?

Возможно не лучший термин подобрал.
Ruby — нет, Python — для лямд нужен специальный синтаксис, PHP — с натяжкой, разве что Scala…

Не знаю кто тут дурак — но точно не человек удивляющийся тому, что фичу, которая нормально поддерживается всеми упомянутыми языками кроме JavaScript объявляют преимуществом именно этого языка…

Дурак очевидно тот, кто утверждает что реализация в Python:
`map(lambda (x,i): ..., enumerate(arr))`
или вот эта фигня из PHP: `array_map(function($x,$i) ..., $arr, array_keys($arr));`
Это совсем не то же самое что в JS: `array.map((x, i) => {...})`

Пипец, как вы этого не видите и продолжаете свою мантру «JS сделал не как у всех»…
Это кто вам сказал? Вот буквально парой комментариев выше нам вроде объясняли что так делать не следует…

Где вы прочитали про «не следует»?
Там речь о том что никто непонятные функции в map просто так не передает. А пример из статьи вообще высосан из пальца.
Просто надо читать спеку и все, а не полагаться на свою интерпретацию и тогда ничего странного не будет.
А когда вам два плюс два сложить хочется — вы тоже спеку читаете? Map'а — она штука фундаментальная, про неё аж целая статья есть в Википедии. То есть для человека, знакомого с функциональщиной — это как операция сложения или как синус. То есть место, где меньше всего ожидаешь подвоха и уж точно не полезешь в спеку про него читать.

А так-то да: многие знания — многия печали, если ничего не знать и воспринимать JavaScript «с чистого листа» — то всё нормально.
А когда вам два плюс два сложить хочется — вы тоже спеку читаете?
Вы не поверьте ©

Например, имеем выражения '2'+2 и '2'*2. Как думаете, не читая документацию и не имея опыт работы с C#, Java, JavaScript, PHP и Python, Вы сможете сказать, каков будет результат этих выражений для каждого языка? Думаю, ответ очевиден: при таких условиях, ни Вы, ни кто-либо другой не сможет правильно ответить на этот вопрос. И в этом нет ничего удивительно, поскольку у каждого языка есть свои тараканы «единственные правильные способы» решить тут или иную задачу.

Вызов map в этой аналогии все-таки эквивалентен именно 2+2, и для такого случая спеку читать большинство людей не будет (и правильно сделает—для большинства языков, кроме javascript).

Читайте эти выражения как getVar() + getInput() и getVar() * getInput(), потом спросите себя, что вызывает больше путаницы для начинающего программиста, который не читает документацию: «неверное» поведение map или «неверный» результат этих выражений?

Я не знаю, откуда у Вас такие данные, что «для такого случая спеку читать большинство людей не будет», но я более чем уверен, что хорошие программисты всё-таки читают документацию. И это правильно.
Например, имеем выражения '2'+2 и '2'*2. Думаю, ответ очевиден: при таких условиях, ни Вы, ни кто-либо другой не сможет правильно ответить на этот вопрос.
На самом деле ответ очевиден: языки, в которых эти выражения вообще имеют какой-то смысл — языки опасные и ими пользоваться не стоит. И да, я знаю, что в python второе выражение имеет смысл — это одно из неудачных мест в этом языке.
Ого! То есть, C#, C++, Go, Java, JavaScript, PHP и другие, это опасные языки и не стоит ими пользоваться? Возможно, только Python правильнее всех, но и у него тоже есть свои «тараканы»?
Получается, нам нужно срочно создать новый идеальный язык?
image

В этих популярных языках сознательно решили обрабатывать данное выражение по-разному и разработчики, которые ежедневно используют эти языки, считают это удобным, при этом могут недоумевать, что в других языках это работает иначе (например, «как это, два+два на одной машине ровно 52, а на второй машине вообще другое значение?» или «почему я должен каждый раз указать тип данных, когда язык может легко угадать делать всё вместо меня?»). Поэтому, если решили работать с новым языком, не пытайтесь сравнивать его с теми языками, с которыми работали ранее. Прежде всего, нужно читать документацию и понять что происходит, а не полагаться на то, что «язык будет делать то, что мне нужно, а не то, что я ему сказал».
Нет, получается, что распространённые языки неидеальны, а идеальные — нераспространены.

Что довольно логично: если вы постоянно выпрявляете «косяки» в языках, то ими, рано или поздно, престают пользоваться (пример: Algol-W, Pacal, Modula-2, Oberon), а если не правите… ну так они и остаются.

Однако из-за того, что все распространённые языки обладают своими граблями — они гряблями быть не перестают. Но PHP и JavaScript особенные: — там плотность граблей такова, что кажется, что язык только из одних граблей и состоит. Хуже только bash… но это, всё-таки не «универсальный язык программирования» и никогда так не позиционировался.
Что касается идеальных языках, Вы не задумались, почему они не стали популярными? Быть может, не такие они уж идеальны? Например, (не считая BASIC, который был лишь детской забавой), мой первый язык программирования был Pascal и, опираясь на мои давние воспоминания, лично я не могу называть его идеальным ЯП. Возможно я ошибаюсь, но мне кажется ни один язык не сможет стать идеальным для всех задач и для всех людей.

Для меня грабли в языках программирования скорее философский вопрос: я пишу на разных языках и почти не вижу никаких проблем с граблями — каждый ЯП это лишь очередной инструмент со своими особенностями. И кстати, возможно, мои задачи не являются комплексными, но мне кажется, в JavaScript исправили одно из фундаментальных граблей: простой способ получить индекс при использовании map. Конечно, это не означает, что я сразу же перейду на JavaScript и буду использовать его вместо Python или PHP.

Кстати, как насчёт «опасных языках» и чтение документации? Вы действительно думаете, что не стоит использовать те языки и что не нужно читать документацию? Спрашиваю, не холивара ради, а потому что ниже Вы пишите правильные вещи (ну, с моей точки зрения), и мне действительно интересен честный ответ на эти вопросы.
Что касается идеальных языках, Вы не задумались, почему они не стали популярными?
Потому что «всюду лошади» (вот эти вот лошади). Невозможно что-то сделать правильно и хорошо с первого раза. Более того, то, что было хорошо 10 лет назад сегодня — может оказаться уже и не таким удачным решением. Но когда вы что-то исправляете — вы возращаетесь, на шкале популярности, назад. Ибо «лошади».

мой первый язык программирования был Pascal и, опираясь на мои давние воспоминания, лично я не могу называть его идеальным ЯП.
Я тоже. Потому что в нём есть проблема «провисающего» else, хотя бы. Зато уже в нём оператор выбора реализован «по-людски». То есть, объективно говоря, Ada или Modula-2 — лучше, безопаснее, чем Pascal, а C или Java — хуже и опаснее. Про JavaScript и PHP я вообще молчу — это не языки, а коллекция граблей.

Однако стоит признать, при этому, что попытки сделать «идеальный» язык (Algol W, Pascal, Modula-2, Ada и Oberon и так далее) привели к тому, что хотя, объективно говоря, каждый следующий язык был лучше предыдущего… в популярности они при этом теряли. До такой степени, что последние версии Oberon — это уже не промышленные языки, а, скорее, «исторический курёз».

А выгрывали языки, похожие на популярные: C, C++, Java, JavaScript. Они все унаследовали от C проблему с идиотским оператором выбора (сколько ошибок произошло от «потерянного» break это ж ни в сказке сказать, ни пером описать… на один случай, когда fallthrough сделан умышленно приходится в среднем, наверное десяток, а то и сотня случаев, когда это сделано по ошибке) и также имеют общую для С и Pascal проблему с else. Из языков в десятке самых популярных только два языка не имеют этой проблемы: Python и, внезапно, Visual Basic .NET.

Но означает ли это, что все эти популярные языки — уродские (да) и их следует избегать (нет)? Нет, потому что качество самого языка — это ещё не всё. Вы можете взять какой-нибудь распрекрасный Oberon… и утонуть в попытка сделать что-либо подобное на Eigenу. В одиночку. С нуля. Вряд ли это будет разумным выбором.

Потому приходится выбирать: брать язык, который не слишком ужасен — и при этом достаточно популярен для того, чтобы вам не пришлось всё «оснастку» писать с нуля.

И кстати, возможно, мои задачи не являются комплексными, но мне кажется, в JavaScript исправили одно из фундаментальных граблей: простой способ получить индекс при использовании map.
Пока вы ещё не привели пример ни одной задачи, при которой вам это было бы нужно. И вопрос: а почему мы передаём в функцию три аргумента, а не, скажем, десять?

Решение, которое использует python мне кажется куда более оптимальным — если вам так уж нужен индекс вариант map(function, enumerate(object)) — всегда к вашим услугам. Незачем для этого ломать простую семантику метафункции map.

Вы действительно думаете, что не стоит использовать те языки и что не нужно читать документацию?
Конечно же документацию читать нужно. Но это не значит, что если в языке что-то сделано нелогично и неудобно, но это всё подробно описано в документации — то это, вдруг, делает язык приемлемым. Потому что каждое место, где что-то сделано нелогично и неудобно — обозначает, что об это место вы будете, потом, больно стукаться. Регулярно. Если не вы, то кто-то из работающих с вами. Как об этот самый дурацкий switch.

И потому, когда вы читаете документацию — всегда полезно соотносить количество «граблей», которые есть в языке и описаны в документации с количеством полезных фич.

В этом смысле лидером, мне кажется, является Python: даже несмотря на динамическую типизацию (которую я не люблю) очень многие вещи там сделаны качественно, интуитивно понятно и не требуют чтения кучи документации, чтобы разобраться в простом фрагменте.

А вот, скажем, C++ — он хорош в другом: там очень много «острых» углов, но если вам нужна максимальная эффективность — то в нём есть много инструментов, которых нет в других языках… возможно сюда, со временем, доберётся Rust… но пока там нет, в стабильной версии, даже вызова ассемблерных вставок — то есть о максимальной эффективности речь [пока?] не идёт. Но за ним я внимательно слежу, это реально может быть замена C++ со временем.

мне действительно интересен честный ответ на эти вопросы.
Честный ответ таков: все популярные языки — неидеальны, но эта неидеальность — разная. Если JavaScript и PHP я буду использовать, разве что, от безисходности — когда у меня нет другого выбора, то вот python или C++ — я вполне могу использовать того, когда выбор есть.

Потому что python — вполне пригодно использовать там, где требования к скорости не критичны. То есть, в первую очередь, во вспомогательных системах, с которым конечный пользователь не сталкивается, но зато сталкиваюсь я: в этом случае для меня не важно, сколько времени потребует программа для работы — важно суммарно время её работы и время её написания.

Писать же неэффективную программу, за которую вам деньги платят, как тут предлагают… ну это халтура просто.

Бытовая аналогия: я, например, если ну очень приспичит, могу разобрать свой лаптоп с помощью вилки и перечинного ножа. Но если я увижу что такое попытается, при мне, проделать ремонтник — я отберу у него лаптоп и откажусь платить деньги. Потому что профессионал — должен обладать профессиональным инструментом и уметь им пользоваться.

Хотя если какой-то самодур заставит профессионалов ремонтировать лаптопы без каких-либо железных предметов (безопасность, всё такое) — я, конечно, посочувствую, похихикаю, но приму их оправдания и пойму почему они все теперь — виртуозы по разборке этих лаптопов зубочистками.

Но вне этого странного места я, всё-таки, буду ожидать использование отвёртки.

То же самое и с программированием: если менеджер порождает скрипт для закачки файлов в VBA в Excel (реальный пример с одним из моих друзей)… да ради бога — чем умеет, тем и порождает.

Если фронтэндер использует JavaScript… ну тут вопросов тоже нету: а что ещё он может использовать?

Или если вам нужен скрипт для установки программ: sh или даже bash — они везде есть, а вот pyhton, увы, через раз — то есть Python 2, то есть Python 3, под каким именем — это тоже неизвестно…

Но вот когда этот же JavaScript на бекэнд тянут… где можно выбрать из кучи других, более вменяемых, языков… тут уже возникают вопросы по поводу профессионализма… в полный рост возникают.

Спасибо большое за столь развёрнутый ответ. Не понимаю, почему Вам поставили минус.

В принципе, со многими мыслями согласен, особенно с тем, что нужно выбрать правильные инструменты и всегда нужно стремиться писать хороший код, скорость и удобочитаемость которого должны быть на первом месте.

Тоже не понимаю эту тягу к использованию JavaScript на бэкенде и для создания десктопных приложений. Ну, я понимаю, когда разработчик, зная лишь JavaScript, делает свой маленький проект, но мне трудно согласиться с теми, кто переходят на JavaScript, несмотря на то, что из-за этого проект будет работать в разы медленнее и будет рождать куча новых интересных приключений.

Тем не менее, я думаю, что плохой код, прежде всего, рождается по вине разработчика. Возможно, это не очень правильная позиция, но лично я не пытаюсь искать слабые места каждого языка. Наоборот, я рассматриваю его сильные стороны в определённый момент для конкретной задачи.

Поскольку моя работа связана с вебом, для меня главные показатели при выборе языка это быстродействие + время разработчики + стоимость поддержки инстанса. Если есть возможность, использую ab и siege, чтобы понять, что должен выбрать. А если нет, просто выбираю технологии, полагаясь на свой интуицию опыт.

Пока вы ещё не привели пример ни одной задачи
Извините, но не заметил такой вопрос. Например, в JavaScript имеем возможность написать this.getAll().map(this.markupRows) а метод markupRows сможет:
— сравнивать текущий элемент с предыдущем/следующим элементом
— узнать еслу текущий элемент это последний/первый элемент
— обработать первые n элементов особым образом
— добавить классы для стилизации таблицы-зебры

а почему мы передаём в функцию три аргумента, а не, скажем, десять?
К сожалению, не могу ответить, поскольку не изучал этот вопрос, но полагаю потому что эти три аргументы более чем достаточно, чтобы принимающая функция смогла обрабатывать текущий элемент в рамках всего списка.

если вам так уж нужен индекс вариант map(function, enumerate(object))
Возможно я ошибаюсь, но думаю что оптимальнее всё-таки использовать map(function, object), при этом map должен передать функции все необходимые аргументы, а уже в function будем решать, что делать с ними (в том числе, игнорировать ненужные аргументы).

если менеджер порождает скрипт для закачки файлов в VBA в Excel
Признаюсь, у меня тоже есть парочку xlsm и docm файлов в которых использую VBA, чтобы при определённых событьях отправить или загрузить данные прямо из Excel или Word. Более того, у меня есть много мелких «помошников» с использованием Autoit, Bash, HTA, Perl, Powershell, Windows Batch. Как правило, они рождались довольно спонтанно и без долгих раздумий (или из желания узнать что-то новое), но для меня важен лишь тот факт, что на протяжения многих лет они делали всю кропотливую работу.
Возможно, это не очень правильная позиция, но лично я не пытаюсь искать слабые места каждого языка.
Как можно осмысленно выбирать языки если не знать и сильных и слабых сторон?

Вы никогда не задумывались почему JavaScript и PHP — это «ужас летящий на крыльях ночи», почему C — это коллекция граблей, за которые вас всё время стремится наказать компилятор и так далее?

Это ведь не случайность. JavaScript и PHP — изначально постулировали задачу «сделать так, чтобы разработчик без опыта мог создать скрипт — он бы начал работать с как можно меньшими усилиями». Какое для этого было выбрано средство? Язык старается «додумывать за программиста — и не всегда успешно. Когда я пишу „333“/3 — я, вообще, чего получить-то хочу? 2222 (111 делённое 3) или „3“ (треть от исходной строки)? Идеи о том, какой тут будет ответ у разных людей могут сильно разниться.

Эта же Mapа с дополнительным аргументом в сочетании с функциями, которые имеют неочевидные дополнительные аргументы… это же всё — из попытки „помочь“.

Только в больших проектах эта „помощь“ боком выходит.

Ну а C — это, напротив, попытка „развязать руки компилятору“ за счёт ограничения программиста. Что, в результате, приводит язык к „близости к железу“ (ибо компилятору не нужно лишних проверок в код вставлять, чтобы a << 257 правильно обработать), а это, в свою очередь — к попыткам использовать C как „переносимый ассемблер“.

Ну и так далее.

А вот эта проблема с else — это уже чистой воды случайность. Можно понять почему так получилось, но глубокой идеи за этим не стоит… особенно в Pascal, где, скажем, record всегда имеет свой end… а вот if — не имеет. Просто недодумали вовремя.

Извините, но не заметил такой вопрос. Например, в JavaScript имеем возможность написать this.getAll().map(this.markupRows) а метод markupRows сможет:
— сравнивать текущий элемент с предыдущем/следующим элементом
— узнать еслу текущий элемент это последний/первый элемент
— обработать первые n элементов особым образом
— добавить классы для стилизации таблицы-зебры
Хорошие примеры. Хотя вопросы безопасности тут сразу встают в полный рост. Потому что представьте себе, что вы добавили „классы для стилизации таблицы“ — а потом, в рекламируемом тут .chained подходе выкинули часть элемнтов? И что будет с вашими „первыми n элементами“, если их число, дальшейними фильтрами, изменится?

Все эти вещи очень-очень сильно выходят за рамки простой концепции Mapы, которая предполагает обработку множества элементов одинаковым образом. И может, в некоторых языках, даже автоматом раскидать эту обработку по разным ядрам процессора — в JavaScript это в принципе невозможно… именно из-за выбранного интерфейса.

Возможно я ошибаюсь, но думаю что оптимальнее всё-таки использовать map(function, object), при этом map должен передать функции все необходимые аргументы, а уже в function будем решать, что делать с ними (в том числе, игнорировать ненужные аргументы).
Ну разумеется нет. Если вы передаёте в function этот самый object — то вы должны гарантировать, во-первых, что этот object во-первых существует, а во-вторых никто к нему, кроме этой функции Map доступа не имеет. Это сериализует всё операцию и очень сильно связывает руки реализации. Dart, кстати, во многом отсюда: разработчики V8 обнаружили, что достигли „потолка“, когда вот эменно подобные „эффективные“ решения не позволяют сделать UI быстрее… и решили всех пересадить на новый язык.

Никакого успеха, понятно, не достигли — но это уже другая история.
И может, в некоторых языках, даже автоматом раскидать эту обработку по разным ядрам процессора — в JavaScript это в принципе невозможно… именно из-за выбранного интерфейса.

И в чем принципиальная проблема раскидать обработку map, даже с дополнительными аргументами, по нескольким процессорам? (то что Array не immutable сейчас нe учитываем)
А что вам мешает ездить на JavaScript-велосипеде по дороге? Отсутствие колёс сейчас не учитываем.
Правильно, ляпнуть какую-нибудь глупость, а когда спросят — отмочить очередную прибаутку про то какой js корявый.
Вы же сами написали: " в JavaScript это в принципе невозможно… именно из-за выбранного интерфейса"
Ну и при чем тут не иммутабельный список? Он и без дополнительных аргументов в .map такой.
Ну и при чем тут не иммутабельный список? Он и без дополнительных аргументов в .map такой.
И ровно поэтому mmap в JavaScript — не Mapа.

У математической функции Map есть в сущности ровно одно несколько фундаментальных свойство: (map f)⚬(map g) = map (f ⚬g). Оно не выполняется в JavaScript ровно потому, что Mapа там — нет Mapа.

Причём этому мешают оба «улучшения», которые имеются в JavaScript: мы можем как изменить объект для которого вызвана Map, но, кроме того, во время обработки — мы обязаны передавать туда объект — который там, в функции, может поменяться.

Если необходиомость передавать индекс — это просто вопрос производительности (для многих структур само вычисление индекса весьма нетривиально, особенно если обработка ведётся на многих ядрах и/или машинах параллельно), то вопрос метабельной коллекции, передаваемой в функцию — это уже более принципиальный вопрос.

P.S. Обратите, кстати, внимание, не мой пример с push и подумайте — сколько «стоит» поддержание всего этого. В том-то и дело, что «улучшенный» интерфейс, принятый в JavaScript — он далеко не бесплатен. Это если даже забыть про «проблемы идиотов-математиков» (а как бы классно без них было… никаких проблем с Mapой, JavaScriptом и компьютерами… в силу отсутствия и первого и второго и третьего)
У математической функции Map есть в сущности ровно одно несколько фундаментальных свойство: (map f)⚬(map g) = map (f ⚬g). Оно не выполняется в JavaScript ровно потому, что Mapа там — нет Mapа.

list.map(x => fun1(x)).map(х => fun2(x)) -> list.map(x => fun2(fun1(x)))

Где тут оно не выполняется?

Да, js позволяет передавать функции по имени, и можно вместо list.map(x => fun(x)) написать list.map(fun) — и вполне логично, что тогда он передаст туда все свои аргументы.

(для многих структур само вычисление индекса весьма нетривиально

В js список — вполне определенная структура.

вопрос метабельной коллекции, передаваемой в функцию — это уже более принципиальный вопрос.

А ничего что у вас и так есть ссылка на этот список?
`list.map(x => list.push(1)) // ?!`
Вы же говорили что именно из-за аргументов передаваемых в map в js его в принципе невозможно распараллелить, что неверно.
Как можно осмысленно выбирать языки если не знать и сильных и слабых сторон?
Прошу отметить, что вырвать фразы из контекста не очень хорошо, ведь я написал другое. Цитирую: «лично я не пытаюсь искать слабые места каждого языка. Наоборот, я рассматриваю его сильные стороны в определённый момент для конкретной задачи». Например, если на php-fpm+nginx я смогу создать некое веб-приложение, которое будет работать на VPS за $2.99, обработать сотни тысячи запросов в день и держать load average ниже 0.1, при этом мне не придётся кувыркаться из-за простых вещей вроде strip_tags, то я не перестану использовать PHP только из-за идеологических соображений. Однако это не означает, что всегда буду использовать PHP. Также как, я не буду рекомендовать кому-либо изучить PHP в качестве первого ЯП (конечно, бывают исключения).

Вы никогда не задумывались почему JavaScript и PHP — это «ужас летящий на крыльях ночи», почему C — это коллекция граблей, за которые вас всё время стремится наказать компилятор и так далее?
Как я уже сказал, для меня каждый язык программирования лишь очередной инструмент и я указал, как выбираю свои инструменты. В таких случаях, лично я, далеко не в первую очередь буду рассуждать о плохом синтаксисе, идеологии или грабли ЯП.

Потому что представьте себе, что вы добавили „классы для стилизации таблицы“ — а потом, в рекламируемом тут .chained подходе выкинули часть элемнтов? И что будет с вашими „первыми n элементами“, если их число, дальшейними фильтрами, изменится?
Во-первых, мой пример уже содержит тот самый .chained, иначе без него я бы написал let users = this.getAll(); users.map(this.markupRows); (т.е. определить ненужную переменную и написать больше кода). Во-вторых, как уже сказал, я считаю, что плохой код рождается по вине разработчика и если разработчик сначала будет сделать всю тяжёлую работу, а потом выкинуть часть обработанных элементов — ни один язык его не спасёт. Для меня выглядит «немного неправильно» получить все записи сортированные в определённом порядке, применить HTML разметку для каждой записи, а потом выкинуть часть элементов.

Все эти вещи очень-очень сильно выходят за рамки простой концепции Mapы, которая предполагает обработку множества элементов одинаковым образом.
Получается, даже разработчики Python нарушают эту концепцию? Например, беглый поиск находит это (уверен, это не единственный случай). Но, главное, мне интересно, где написано, что нужно обрабатывать элементы одинаковым образом? Например, Википедиа говорит, что map применяет некую функцию к каждому элементу списка и возвращает обработанные элементы в том же порядке. Лично я не видел какие-либо ограничения, на что должна возвращать функция, также как и какие аргументы, она должна получать. И разве, это не те «самые лошади», когда другие не могут усовершенствовать функцию из-за боязни/нежелании сломать «старые концепции»?

Ну разумеется нет. Если вы передаёте в function этот самый object — то вы должны гарантировать, во-первых, что этот object во-первых существует
Если честно, не понял, что Вы имеете в виду, и как передача дополнительных аргументов влияет на это.

а во-вторых никто к нему, кроме этой функции Map доступа не имеет.
Хм. Почему никто не должен иметь доступ к этому объекту?
Для меня выглядит «немного неправильно» получить все записи сортированные в определённом порядке, применить HTML разметку для каждой записи, а потом выкинуть часть элементов.
А почему, собственно? Вы когда-нибудь Excel'ем или Google Docs пользовались? Там фильтры есть. Можно выкинуть все строчки со словом «красный» или с числами больше 100 или ещё какие-нибудь. И таблички с кнопочками которые реагируют на эти действия. Вы что — считаете, что это нормально, когда на каждый чих табличка формируется с нуля?

Во-вторых, как уже сказал, я считаю, что плохой код рождается по вине разработчика и если разработчик сначала будет сделать всю тяжёлую работу, а потом выкинуть часть обработанных элементов — ни один язык его не спасёт.
Плохой код рождается от непонимания того, что и где у вас происходит в программе, в первую очередь. А для такого понимания — нужно, чтобы программа состояла из простых компонент. «Обработать 100 элементов по одному и вернуть их» — это простая концепция. Mapа в JavaScript — сложная. Ну вот просто сложная. Вот вы можете сказать что сделает вот такой простой код:
[1, 2, 3].map((x, i, a) => a.push(i))
Ну там, по наитию, не читаю мануалы до посинения? А почему?

Я где-то читал классную фразу «Good language have to be not just easy to use, but it should be hard to abuse». При этом вторая часть — на самом деле важнее первой.

Получается, даже разработчики Python нарушают эту концепцию? Например, беглый поиск находит это (уверен, это не единственный случай).
Я не знаю что именно вы искали и почему то, что вы нашли нарушает концепцию Mapы, извините.

Лично я не видел какие-либо ограничения, на что должна возвращать функция, также как и какие аргументы, она должна получать.
А очень просто — в той же википедии, если бы прочитали статью до конца, вы бы увидели там фундаментальное свойство Mapы:
(map f)⚬(map g) = map (f ⚬g).

Это такое же фундаментальное свойство Mapы, как коммутативность у сложения или умножения. Это, собственно, то, что делает Mapу Mapой и над которой потом строятся другие вещи (типа MapReduce).

В JavaScript Mapа — она, я извиняюсь, не Mapа. Так зачем использовать неподобающее имя?

И разве, это не те «самые лошади», когда другие не могут усовершенствовать функцию из-за боязни/нежелании сломать «старые концепции»?
Отчасти да. Накидайте-ка ссылок на научные журналы с обсуждением функций высшего порядка, совместимых с примером выше? Нету? А почему нету?

А я отвечу почему: потому что нельзя создать теорию «кучи мусора».

Ну разумеется нет. Если вы передаёте в function этот самый object — то вы должны гарантировать, во-первых, что этот object во-первых существует
Если честно, не понял, что Вы имеете в виду, и как передача дополнительных аргументов влияет на это.
Очень просто. Возьмите тот же самый MapReduce. Когда мы обрабатываем петабайты данных. Что мы должны передать в Mapу в качестве третьего аргумента и зачем? Или вот такой код
def HelloReader():
   with open('hello.txt') as hello:
     for line in hello:
       yield line

map(lambda(x) : "| " + x, HelloReader())
Тут, вы, конечно, можете передать в Mapу генератор — но какой в этом смысл и что вы там с ним будете делать? А что будет происходить с вашей Mapой если функция начнёт из контейнера объекты удалять?

Например, если на php-fpm+nginx я смогу создать некое веб-приложение, которое будет работать на VPS за $2.99, обработать сотни тысячи запросов в день и держать load average ниже 0.1, при этом мне не придётся кувыркаться из-за простых вещей вроде strip_tags, то я не перестану использовать PHP только из-за идеологических соображений.
А зачем мне может потребоваться такое приложение? Если это мой проект — то я, уж как-нибудь найду $5, чтобы не вмазываться в это гуано, а если это на заказ, то я просто не буду с ним связываться. Потому что если у закачика нету $50-60 в год на оплату хостинга, то откуда у него возьмутся какие-то деньги, чтобы заплатить за работу мне?

Времена, когда форум на PHP можно было захостить за $15-20 в месяц, а личная VDS с гигабайтом памяти начиналась от $200-$500 — в далёком-далёком прошлом. Сегодня за $5 в месяц можно получить гиг памяти и 25GB на SSD — чего хватает даже для каких-нибудь Enterprise Java решений под небольшую нагрузку. Зачем, в этих условиях, связываться с PHP — я представить себе не могу.
А почему, собственно?
Поскольку для меня выкинуть это:
return this.getAll().map(this.markupRows).discardSomeRows()

Вы что — считаете, что это нормально, когда на каждый чих табличка формируется с нуля?
Нет, конечно. И я этого не сказал. Хотя уж точно есть задачи, когда эффективнее применить разметку заново.

Плохой код рождается от непонимания того, что и где у вас происходит в программе, в первую очередь. А для такого понимания — нужно, чтобы программа состояла из простых компонент.
Спросите начинающего программиста, что делает map(lambda(x) : "| " + x, HelloReader()) и насколько это легко читается. Также, положа руку на сердце, скажите, что никогда не видели плохой код написанный на Python.

Вот вы можете сказать что сделает вот такой простой код: [1, 2, 3].map((x, i, a) => a.push(i))
То есть, придумываем «интересную задачу», потом виним язык, что делает «неправильные» вещи? Тогда встречный вопрос, что будет выводить следующий код и насколько интуитивно понятен результат с точки зрения новичка?
values = [['a!'], ['b!'], ['c!']]
print(map(lambda v : v.append('x!'), values))

А этот?
values = ['a!', 'b!', 'c!',]
print(map(lambda v : v is 'b!', values))

Я не знаю что именно вы искали и почему то, что вы нашли нарушает концепцию Mapы, извините.
Ну почему же Вы так? Я ведь специально цитировал Ваши слова, причём мне кажется сложно забыть собственные слова, когда выделяете их полужирным текстом. Цитирую: «Все эти вещи очень-очень сильно выходят за рамки простой концепции Mapы, которая предполагает обработку множества элементов одинаковым образом». Объясняю: «по той ссылке есть код, который с этой точки зрения, технически, не отличается от моего примера». И нет, я не сказал, что тот код нарушает «концепцию map», я имел в виду, что он нарушает «Вашу концепцию».

А очень просто — в той же википедии, если бы прочитали статью до конца, вы бы увидели там фундаментальное свойство Mapы: (map f)⚬(map g) = map (f ⚬g)
Знаете, это очень сильное утверждение, которое очень многое меняет. Поэтому, хотел бы узнать, что же это означает? Почему функция не может обрабатывать элементы по-разному? Почему map не может передать несколько аргументов? Как можно доказать это уравнение в Python? Почему данное «фундаментальное свойство» нарушается в JavaScript?

Так зачем использовать неподобающее имя?
Возможно, всё-таки это правильное имя, учитывая что она применяет функцию к каждому элементу списка?

Отчасти да.
Вот и я о том же. Только, трудно признать это удобным, если такое изменение появилось в «неправильном ЯП»?

Накидайте-ка ссылок на научные журналы с обсуждением функций высшего порядка, совместимых с примером выше? Нету? А почему нету?
Я не искал таких ссылок. Но я буду очень признателен, если Вы поделитесь ссылками на научные журналы, где рассказывают, почему map не может передать несколько аргументов и почему функция не может обрабатывать элементы по-разному.

Когда мы обрабатываем петабайты данных. Что мы должны передать в Mapу в качестве третьего аргумента и зачем?
Например, у нас есть обменные курсы из разных источников за пару лет и при применении map хотим чтобы функция имела возможность сравнивать каждый день с другими днями из всего списка и проводить определённые операции.

Тут, вы, конечно, можете передать в Mapу генератор — но какой в этом смысл и что вы там с ним будете делать?
В этом конкретном примере — ничего не нужно делать. Как я уже сказал раньше, если Вам не нужны дополнительные аргументы, просто игнорируйте их. А если кому-то нужны — пусть использует их на здоровье.

А что будет происходить с вашей Mapой если функция начнёт из контейнера объекты удалять?
Лично я считаю, что map не должен изменить обрабатываемый список. Если же решили сделать это, убедитесь, что понимаете, что происходит. То есть, угадать это недостаточно.

А зачем мне может потребоваться такое приложение?
Я и не сказал, что Вам нужно создать такое приложение (хотя я допускаю, что как пользователь Вы пользуйтесь подобными, просто Вы не знаете этого). Я лишь хотел намекнуть, что правильно выбирая свои инструменты, можно добиться очень хорошими результатами не тратя время и деньги впустую.

Если это мой проект — то я, уж как-нибудь найду $5, чтобы не вмазываться в это гуано
А вот это, мягко говоря, непрофессионально. Как Вы можете написать такое, не зная, что это за приложение и какие данные оно обрабатывает? Вы думаете, что сервер в два раза дороже гарантирует вдвое более мощности? Или что «гиг памяти и 25GB на SSD» обязательно сделает любое приложение быстрее? А если и так, Вы ведь понимаете, что если на слабой машине технология X была в десять раз быстрее чем Z, то на более мощной машине это соотношение практически не меняется?

Чтобы не было вопросов, почему иногда я выбираю ту или иную технологию, напомню, что делаю это неспроста, а потому что, например, ab и siege подсказывают, какая технология будет обработать больше всего запросов. Ну, а для тех, кто не любит проводить тесты самостоятельно, рекомендую: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/php.html
Тогда встречный вопрос, что будет выводить следующий код и насколько интуитивно понятен результат с точки зрения новичка?

values = [['a!'], ['b!'], ['c!']]
print(map(lambda v : v.append('x!'), values))


А этот?

values = ['a!', 'b!', 'c!',]
print(map(lambda v : v is 'b!', values))
В обоих случаях будет выведено что-то типа <map object at 0x7fbcfd40eba8>, потому что вы генератор не превратили в печатный объект. Это, как раз, нормально новичками принимается. Или вы о чём-то другом? Тогда нельзя ли, всё-таки, сказать: чем именно вы недовольны. Тем что map возвращает не список, а генератор, тем что append возвращает None или тем, что is и == ведут себя по разному?

Из всего этого разнообразия меня удивило, когда я впервые столкнулся с python, разве что тот факт, что append ничего не возвращает — но в приличных тьюториолах на это особо обращается внимание… так что это может быть не самое логичное решение в языке, но если ворон на уроках не считать и не пробовать писать на python не читая доки вообще (как я лет 10 назад) — то неожиданностей быть не должно.

Ну почему же Вы так? Я ведь специально цитировал Ваши слова, причём мне кажется сложно забыть собственные слова, когда выделяете их полужирным текстом. Цитирую: «Все эти вещи очень-очень сильно выходят за рамки простой концепции Mapы, которая предполагает обработку множества элементов одинаковым образом». Объясняю: «по той ссылке есть код, который с этой точки зрения, технически, не отличается от моего примера». И нет, я не сказал, что тот код нарушает «концепцию map», я имел в виду, что он нарушает «Вашу концепцию».
От объяснения легче не стало. Может вы не туда ссылку дали? Я вижу там такой код:
        if isinstance(node, Tuple):
            return tuple(map(_convert, node.elts))
        elif isinstance(node, List):
            return list(map(_convert, node.elts))
...
Он использует Mapу в полном соответствии с её описанием в Wikipedia. Либо объясните где вы видите тут нарушение концепции, либо дайте ссылку на тот код, который что-то там нарушает.

Поэтому, хотел бы узнать, что же это означает?
Это обозначает что объекты обрабатываются Mapой независимо. И функция, которая их обрабатывает не знает контекста. То есть, соответственно, можно запускать такую функию на объектах в любой последовательности и, в частности, на разных машинах. См. MapReduce и всё прочее.

Почему функция не может обрабатывать элементы по-разному?
Потому что в этом случае разбиение большой Mapы на две маленькие или, наоборот, их слияние — дадут неверный результат.

Почему map не может передать несколько аргументов?
Именно потому что передача аргументов, не имеющих отношения к объектам бессмысленна (что вы туда передавать будете? постоянную тонкой структуры? зачем?), а передача информации об обрабатываемой последовательности — сделает Mapу — не Mapой.

Как можно доказать это уравнение в Python?
Это можно сделать только при определённых допущениях. Например вы можете сами положить ваш список в глобал и, соотвественно, оттуда функция обработки его достанет. Если же вы подобных «финтов ушами» не совершали, то у функции обработки просто нет информации, позволяющей одинаковые элементы, стоящие на разных местах обрабатывать по разному. И, поскольку у неё нет доступа к оригинальной последовательности — то её она испортить тоже не может.

Почему данное «фундаментальное свойство» нарушается в JavaScript?
Ровно из-за передачи пары дополнительных аргументов.

Только, трудно признать это удобным, если такое изменение появилось в «неправильном ЯП»?
Нетрудно. Я, собственно, даже не против подобной функции. Только не называйте её Mapой! Назовите, как в C++, transform или там foreach. Да как угодно назовите — только уберите ментальную связь с лямбда-исчислением.

Но я буду очень признателен, если Вы поделитесь ссылками на научные журналы, где рассказывают, почему map не может передать несколько аргументов и почему функция не может обрабатывать элементы по-разному.
Вы ещё ссылки на статьи, где объясняется почему угол в равностороннем треугольнике — не нужно называть «прямым». Именно не доказательство того, что он не «прямой». А объяснение того, чем плохо называть его прямым.

А чо? Назовём угол в 60 градусов прямым, создадим «альтернативную геометрию». Удобно же. Нет таких. А почему нет, собственно?

Mapа просто определяется в лямбда-исчислении определённым образом — и дальше так и используется. И да, таких статей научных — достаточно. А вот таких, где была бы под Mapой понималось нечто странное, в духе JavaScript — я не видел.

Например, у нас есть обменные курсы из разных источников за пару лет и при применении map хотим чтобы функция имела возможность сравнивать каждый день с другими днями из всего списка и проводить определённые операции.
Если это действительно нужно, то нужно эту информацию передать в функция явно. Кроме того, если у вас действительно петабайты этих самых обменных курсов, то, возможно нужно обработку вести каким-то другим способом, а не передавая петабайт данных функции, обрабатывающей один элемент.

А если кому-то нужны — пусть использует их на здоровье.
А нельзя, наоборот, не тратить время на вычисление ненужной информации? А то так можно ещё туда календарь на текущий год передать и кусрсы валют на сегодня. Четвёртым и пятым параметром. А чего? Вдруг пригодится.

А что будет происходить с вашей Mapой если функция начнёт из контейнера объекты удалять?
Лично я считаю, что map не должен изменить обрабатываемый список.
Это замечательно если фунцию писали вы. А если нет? У нормальных людей всё гораздо проще: функция не может изменить объект, доступа к которому у неё нет. И всё. И не нужно читать её код, чтобы понять — разделяют вашу религию разработчики или нет… хотя в языке, где считается нормальным, что имена локальных переменных меняют поведения функций… это, наверное, считается необходимым…

Я лишь хотел намекнуть, что правильно выбирая свои инструменты, можно добиться очень хорошими результатами не тратя время и деньги впустую.
Я вот в этот не уверен. Потому что практически я наблюдаю буквально человеко-годы, которые выбрасываются на подобные «хорошие результаты».

То есть я принимаю ситуация, когда кто-то, специалист не в программировании, а, не знаю, в торговле на бирже или в проектировании холодильников, творит что-то вот этакое на JavaScript… просто потому что в Python или Haskell он не умеет — ну а потом, понятно, специалистам это расхлёбывать. Это — нормально.

Но мы-то вроде, говорим о другом, о том, что вы, как специалист, что-то такое хотите создать. Неважно даже — имея прототип на .BAT-файлах или Pascal, неважно.

Тут-то откуда PHP может возникнуть?

Как Вы можете написать такое, не зная, что это за приложение и какие данные оно обрабатывает?
Очень просто: я просто тупо приплюсовываю к цене вашего хостинга цену за пару часов моей работы.

Или что «гиг памяти и 25GB на SSD» обязательно сделает любое приложение быстрее?
Нет, этот сервер просто позволит мне не пытаться пользоваться опасными инструментами. И если это даст экономию в пару часов моего рабочего времени в год — то он себя окупит.

Вы ведь понимаете, что если на слабой машине технология X была в десять раз быстрее чем Z, то на более мощной машине это соотношение практически не меняется?
Извините — но это неправда. Всё зависит от того, что именно ваше приложение хранит в памяти между запросами.

Но даже и это неважно: важно не только то, какой скорости вам позволит та или иная технология (если бы это было так, то мы бы писали всё до сих пор на ассемблере), а в какую цену вам обойдётся разработка плюс хостинг. И если вам потребуется заплатить чуть больше за более дорогой хостинг, но при этом вы сделаете систему быстрее и ошибок там будет меньше — то это вполне неплохой компромисс. PHP недаром на 7м месте сейчас и уверенно движется к вылету из десятки — а когда-то, было время, в тройку входил…

Чтобы не было вопросов, почему иногда я выбираю ту или иную технологию, напомню, что делаю это неспроста, а потому что, например, ab и siege подсказывают, какая технология будет обработать больше всего запросов.
Больше всего запросов вам позволит обработать модуль на C++ для NGINX. Но это не значит, что я для каждого сайта буду его писать. Хотя, в зависимости от задачи, вполне умею и его изобразить.

Ну, а для тех, кто не любит проводить тесты самостоятельно, рекомендую: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/php.html
Что этой ссылкой вы пытаетесь доказать? Что оба языка имеют скорость между «жутко медленно» и «о… ть как медленно»? Если вы уж так любите эту пузомерку — то взгляните уж сюда.

Если у меня будет стоять задача сделать что-то быстрое и затраты на VPS будут меня реально напрягать — я не буду делать это ни на JavaScript, ни на PHP, ни на Python. Ибо в этих случаях выбор — из двух вариантов: C++ или, возможно, Java. В последнее время к этому списку ещё Rust добавился (но на нём разработчиков пока не так много), или, если у вас есть разработчики под Windows — можно C# взять (но у него проблемы с кросс-платформенностью).

Если же я вообще рассматриваю как вариант PHP, Python или JavaScript — то это значит, что скорость работы для меня не критична. И в этом случае ссылаться на скорость работы PHP не очень интересно.
В обоих случаях будет выведено что-то типа <map object at 0x7fbcfd40eba8>, потому что вы генератор не превратили в печатный объект.
Вы точно уверены в этом? ;)

Это, как раз, нормально новичками принимается.
Даже тем, кто перешли со второй ветки на третьей?

Тогда нельзя ли, всё-таки, сказать: чем именно вы недовольны.
Я не говорил, что недоволен языком. Я считаю неправильным пытаться доказать, что язык плох или непонятен, приведя «забавные» куски кода. Моими примерами я лишь хотел намекать, что в Python (как и в случае с JavaScript или другим ЯП) без чтения документации могут возникнуть определённые трудности.

тем что append возвращает None [...] Из всего этого разнообразия меня удивило, когда я впервые столкнулся с python, разве что тот факт, что append ничего не возвращает — но в приличных тьюториолах на это особо обращается внимание… так что это может быть не самое логичное решение в языке, но если ворон на уроках не считать и не пробовать писать на python не читая доки вообще (как я лет 10 назад) — то неожиданностей быть не должно.
Уверен, не только Вас удивило. Но, как я уже говорил ранее и как сейчас Вы сами признали, не нужно пытаться угадать, ведёт себя ЯП логически или нет, просто нужно читать документацию и понять как всё работает. Да, иногда некоторые моменты обнаруживаются с опытом, но считаю неправильным оскорблять разработчиков, по крайне мере, потому что они дают людям бесплатные инструменты, с помощью которых они зарабатывают на жизнь. И не важно, что это за язык.

или тем, что is и == ведут себя по разному?
Какое отношение имеет is к ==? Я имел в виду, что здесь можем столкнуться с нелогичным поведением оператора is или функцией id(). Например, могут возникнуть вопросы, почему указанный мной код возвращает [False, False, False] а вот b = 'b!'; print b is 'b!' возвращает True.

От объяснения легче не стало. Может вы не туда ссылку дали? Я вижу там такой код: [...] Он использует Mapу в полном соответствии с её описанием в Wikipedia. Либо объясните где вы видите тут нарушение концепции, либо дайте ссылку на тот код, который что-то там нарушает.
Если Вас смущает, то, что в моих примерах «элементы обрабатываются по-разному», то Вас должно смущать и тот код, где элементы также не будут «обрабатываться одинаковым образом». И ещё раз: я не сказал, что тот код нарушает «концепцию map».

Это обозначает что объекты обрабатываются Mapой независимо [...] А вот таких, где была бы под Mapой понималось нечто странное, в духе JavaScript — я не видел.
Вы точно-точно уверены, что (map f)⚬(map g) = map (f ⚬g) это и означает? Давайте я покажу Вам пример кода, который объясняет это уравнение, показывает почему Ваши рассуждения неверны и почему JavaScript не нарушает «фундаментальную концепцию map»:
function f(n) {
    return 'F' + n;
}

function g(n) {
    return 'G' + n;
}

function fg(n) {
    return f(g(n));
}

var values = [1, 2, 3];

console.log(values.map(g).map(f));
//-> ["FG1", "FG2", "FG3"]

console.log(values.map(fg));
//-> ["FG1", "FG2", "FG3"]


Только не называйте её Mapой! Назовите, как в C++, transform или там foreach.
Вам не кажется, что transform и foreach, это немного другое? При этом, Вы уверены что завтра не будут обвинять JavaScript, что нарушает «концепцию foreach»? Кстати, в JavaScript есть forEach.

Вы ещё ссылки на статьи, где объясняется почему угол в равностороннем треугольнике — не нужно называть «прямым». Именно не доказательство того, что он не «прямой». А объяснение того, чем плохо называть его прямым. А чо? Назовём угол в 60 градусов прямым, создадим «альтернативную геометрию». Удобно же. Нет таких. А почему нет, собственно?
Нет, спасибо. Я спросил о другом. Дело в том, что для меня выглядит странным, то, что Вы говорите «JavaScript нарушает фундаментальную концепцию map поскольку (map f)⚬(map g) = map (f ⚬g) и это означает, что map не может передать дополнительные аргументы и функция не может обработать элементы по-разному», при этом требуете ссылки на научные журналы доказывающие, почему некоторые разработчики считают, что Вы неверно интерпретируете описание функции map.

Если это действительно нужно, то нужно эту информацию передать в функция явно.
А разве в JavaScript это не передаётся явно?

Кроме того, если у вас действительно петабайты этих самых обменных курсов, то, возможно нужно обработку вести каким-то другим способом, а не передавая петабайт данных функции, обрабатывающей один элемент.
Вы верно отметили: «возможно». Ведь проведение тестов ещё не отменили. К тому же, может оказаться, что функция map оптимизирована таким образом, что необязательный аргумент не влияет отрицательно на производительность, когда создание копии переменной вполне может.

А нельзя, наоборот, не тратить время на вычисление ненужной информации? А то так можно ещё туда календарь на текущий год передать и кусрсы валют на сегодня. Четвёртым и пятым параметром. А чего? Вдруг пригодится.
Если Вам не нужны эти аргументы и у Вас нет подобных задач — просто игнорируйте их. JavaScript позволяет Вам этого делать. К тому же, для меня выглядит неправильно судить других по себе и решить за них, что им должно быть удобнее.

Это замечательно если фунцию писали вы. А если нет?
То же самое можно сказать про любой язык и любой функции. Я не припомню точно, но, почти уверен, что видел код, написанный на Python, который менял обрабатываемый список. Не стал искать примеры, но знаю, что по крайне мере в Python это возможно через self.mylist или global.

Тут-то откуда PHP может возникнуть?
быстродействие + время разработчики + стоимость поддержки инстанса

Очень просто: я просто тупо приплюсовываю к цене вашего хостинга цену за пару часов моей работы.
Ну да, платить больше за хостинг всегда проще. Но если окажется, что разработка на PHP занимает меньше времени, при этом приложение работает быстрее и потребляет меньше ресурсов?

Извините — но это неправда. Всё зависит от того, что именно ваше приложение хранит в памяти между запросами.
Согласен. Но, мне кажется, для большинство задач связанные с вебом данное соотношение не будет меняться. В любом случае, именно поэтому нужно всё тщательно тестировать.

Но даже и это неважно: важно не только то, какой скорости вам позволит та или иная технология (если бы это было так, то мы бы писали всё до сих пор на ассемблере), а в какую цену вам обойдётся разработка плюс хостинг.
Именно это я и сказал с самого начала. Только Вы упускаете из виду, что «цена за разработку плюс хостинг» и «быстродействие приложения» могут жить дружно.

И если вам потребуется заплатить чуть больше за более дорогой хостинг, но при этом вы сделаете систему быстрее и ошибок там будет меньше — то это вполне неплохой компромисс.
А иногда можно делать систему быстрее и стабильнее, при этом платить меньше за хостинг.

PHP недаром на 7м месте сейчас и уверенно движется к вылету из десятки — а когда-то, было время, в тройку входил
В данный момент лично меня не волнует, сколько страниц возвращает Google по запросу «PHP» или «Python». Но если мне придётся выбрать технологию согласно «тренду», то я буду руководиться звёздочками на Github.

Больше всего запросов вам позволит обработать модуль на C++ для NGINX. Но это не значит, что я для каждого сайта буду его писать. Хотя, в зависимости от задачи, вполне умею и его изобразить.
Как я сказал, для меня важно «быстродействие + время разработчики + стоимость поддержки инстанса». Поскольку я не пишу на C++, в зависимости от задачи, выбираю лишь оптимальные технологии из того, что лично я умею готовить.

Что этой ссылкой вы пытаетесь доказать? Что оба языка имеют скорость между «жутко медленно» и «о… ть как медленно»? Если вы уж так любите эту пузомерку — то взгляните уж сюда.
Если для Вас скорость и потребление ресурсов лишь пузомерки, не означает, что другие разработчики думают также, и думаю, что Вы ведёте себя неправильно оскорбляя их за это и за то, что они не разделяют Вашу точку зрения.

На самом деле, я лишь хотел показать, что есть задачи, для которых Python будет работать в разы медленнее и будет потреблять больше ресурсов, чем PHP. Если добавить к этому, то что, например, такие задачи решаются довольно быстро на PHP даже по сравнению с C++ (не говоря уже о Java) — то лично для меня выбор очевиден.

Даже больше скажу: если окажется, что кто-то выбрал node.js вместо Python или PHP, я не стану его судить, ведь может оказаться, что, например, есть задачи, которые выполняются в node.js в 33 раз быстрее чем в Python и 13 раз быстрее чем в PHP.

И самое главное: хоть я считаю, что в определённых ситуациях какое-то решение лучше с разных точках зрения, я не призываю Вас перестать использовать Python, также как и не обзываю то, что делаете Вы. Я лишь хотел донести до Вас, почему некоторые разработчики могут выбрать «неправильные ЯП». С другой стороны, Ваши заявления и оскорбления лишь доказывают, что Вами руководит не профессионализм, а фанатизм.
Но вот когда этот же JavaScript на бекэнд тянут… где можно выбрать из кучи других, более вменяемых, языков…


можно… но зачем?
А когда вам два плюс два сложить хочется — вы тоже спеку читаете?
Но в первый раз вообще читаю, да. Нет привычки фантазировать за авторов, а потом еще и жаловаться на свою же лень прочитать спеку. Количество миносв к предыдущему посту, говорит лишь о качестве программистов, которые не копают чуть глубже.

javascript язык с динамическими типами, по этому надо всегда понимать какая сигнатура метода будет вызывана и с какими аргументами, более того приколов с преобразованием типов полно. Очевидно что в языке динамическая типизация добавляет сложности и это потенциально слабое место, а значит ему надо уделить больше внимания.
А синус тоже может принимать и радианы и градусы и грады, прежде, чем воспользоваться уточню единицы.
А синус тоже может принимать и радианы и градусы и грады, прежде, чем воспользоваться уточню единицы.
Ну и в каком языке он принимает грады по умолчанию, извините?

Импортозамещение и не до такого доведёт...

Ну и в каком языке он принимает грады по умолчанию, извините?
Не знаю, не интересовался. То, что мейнстримовые языки используют радианы, далеко не повод рассуждать так обо всех языках.
МК-61, и не по умолчанию, а по положению переключателя на клавиатуре.
>javascript язык с динамическими типами, по этому надо всегда понимать какая сигнатура метода будет вызывана и с какими аргументами…
ужс!
Я уже настолько привык, что такие вещи мне помогает контролировать компилятор, что сейчас для меня это уже дико.
У нас туда даже пройдя ревью, и цепкие лапы QA к клиентам баги попадают, а если ещё и вот такое стрелять будет… Нет, спасибо: в жизни и так достаточно сложностей, а моё внимание и память не безграничны. И вообще, в отличие от языков курильщика, компилятор здорового человека не позволяет себе ногу отстрелить, по крайней мере не таким примитивным способом.
Я вот об этом:
        static void Main(string[] args)
        {
            //WARNING - CS0642 : Возможно ошибочный пустой оператор
            for (long i = 0; i < int.MaxValue; i++);{}

            double a, b, c; //WARNING -CS0168
            a = b = 1; //WARNING -  CS0219

           var dsf = new int[] {1, 2, 3};
           //ERROR CS1661: Невозможно преобразовать "лямбда-выражение" к типу делегата "System.Func<int,int,double>",
           //поскольку типы параметров не совпадают с типами параметров делегата

           //ERROR CS1661: Невозможно преобразовать "лямбда-выражение" к типу делегата "System.Func<int,int,double>",
           //поскольку типы параметров не совпадают с типами параметров делегата
          Enumerable.Select<int, double>( dsf, ( double p1, double p2) => { return p1 * p2;});
        }
JavaScript — это не «язык курильщика», а «язык менеджера».

Там, где вы закроете одну таску, человек работающий на JavaScript, закроет десять. И неважно, что у него на это уйдёт вдвое больше времени, и что девять из этих десяти будут следствиями «закрытой» первой.

На графике у менеджмента у вас будет сиротливо висеть одна закрытая за пару дней таска, а у JavaScript-разработчика две, а то и три в день.

Так кто лучше работает?
Десять тасков, где 9 — следствие криво закрытой первой, — это неверный подход. Правильный подход — переоткрывать таску до тех пор, либо пока фича не будет работать, либо пока нерадивого «менеджера» не уволят.
У нас переоткрывают. Логика простая: высокому начальству не интересно сколько тасок закрыто. Интересно какие фичи реализованы, и что пойдёт в текущий релиз (например, что будет в release notes).

Количество тасок — это очковтирательство.
У нас переоткрывают.
А как это делается, извините? Ну вот представьте себе: вы закрыли таску «добавить иконку в профиль пользователя». А через неделю открыли другую «в сводной таблице нет информации и количестве покупателей, купивших товар». Как вы вообще поймёте, что эти таски связаны? И что покупатели пропали потому что в поле «Фамилия» у вас теперь не строка, а сложный объект со ссылкой на иконку?

Да, вы проведёте расследование, возможно, укажите на то, что эти таски связаны… но это уже потом — в процессе решения проблемы!

Как «переоткрыть таску» увидев таблицу с пустой колонкой — ума не приложу.
>А как это делается, извините? Ну вот представьте себе: вы закрыли таску «добавить иконку в профиль пользователя». А через неделю открыли другую «в сводной таблице нет информации и количестве покупателей, купивших товар».

Не, не так. У нас взмах крыла бабочки к взрыву сверхновой не приводит. Такие таски чаще всего переоткрываются с «у части пользователей неверная иконка, или её нет», или «в логах NullReferenceException». Происходит это потому, что иконки/картинки/подсказки часто зависят от локали пользователя или от его организации. Т.е., например, в базовой версии c культурой en-us всё хорошо, а в кастомизированной с испанской локалью — нет. Или «шаг вперёд — шаг назад иконка пропадает».
Не, не так. У нас взмах крыла бабочки к взрыву сверхновой не приводит.
Ну так то у вас. У вас её и добавить-то за час, засунув в поле, которое, так-то, строку должно содердать, маленькую структурку в одном месте, а потом «вернуть всё взад» в другом, не получится.

А в JavaScript — вполне. Потому и получаем «язык менеджера», что таски закрываются быстро, бурно, понять — кто именно налажал, зачастую тяжело (так что и наказывать-то обычно некого). Красота же.

А что результат дерьмо — ну так это ещё осознать нужно, что, при отсутствии вот совсем-совсем прямого конкурента — не так-то просто сделать…
Map'а — она штука фундаментальная, про неё аж целая статья есть в Википедии.

Ну вот вам цитата из вашей ссылки на википедию:
map — функция высшего порядка, используемая во многих языках программирования, которая применяет данную функцию к каждому элементу списка, возвращая список результатов. При рассмотрении в функциональной форме она часто называется «применить-ко-всем».

Чем Array.map в js не соответствует этому описанию?

То есть место, где меньше всего ожидаешь подвоха и уж точно не полезешь в спеку про него читать.
И конечно то самое место, куда будешь пихать любую функцию, независимо от ее аргументов…
Чем Array.map в js не соответствует этому описанию?
Хотя бы тем, что вы не можете гарантировать, что вызов функции для одного элемента будет зависеть только от этого элемента. Всё из той же статьи:

Математическая основа операции map позволяет проводить множество оптимизаций.
(map f · map g) xs (где «·» — оператор композиции функций) эквивалентно map (f · g)
то есть (map f)⚬(map g) = map (f ⚬g). Эта оптимизация избавляет от необходимости в двукратном вызове map за счёт совмещения применения функций f и g.
Так вот, сюрприз-сюрприз, для Javascript — эта оптимизация невозможна. Именно из-за того, что map тут — это не map, а чёрт знает что.

И конечно то самое место, куда будешь пихать любую функцию, независимо от ее аргументов…
Ну, как бы, ты ожидаешь, что аргумент-то будет один, да.

Но как я уже сказал, главная проблема Mapы в JavaScript — это не проблема на КДПВ (это впросто завлекуха), а в том, что Mapа в JavaScript — это не Mapа, == — это не операция сравнения, < и > — это не операции порядка и так далее. Подвох на каждом шагу. Хуже, чем в C.
Хотя бы тем, что вы не можете гарантировать, что вызов функции для одного элемента будет зависеть только от этого элемента.
Не понял. Вот вызов для одного элемента — `['1'].map(Number)` Что тут нельзя гарантировать?

Так вот, сюрприз-сюрприз, для Javascript — эта оптимизация невозможна. Именно из-за того, что map тут — это не map, а чёрт знает что.
Как это невозможна?
Вместо list.map(fun1).map(fun2) можно писать: list.map(x => fun2(fun1(x)))
Если я неправильно понял — можете привести правильный пример на Python/Ruby?

Mapа в JavaScript — это не Mapа, == — это не операция сравнения, < и > — это не операции порядка и так далее. Подвох на каждом шагу.
Во-первых, не путайте Map() и .map(), все-таки разные вещи.
И что за «операции порядка»? Они не гуглятся.
Во-вторых, да — в JS есть исторические косяки. Люди, которые на нем пишут не первый день о них знают, это не проблема.
Не понял. Вот вызов для одного элемента — ['1'].map(Number) Что тут нельзя гарантировать?

Речь о другом. Если мы передаём в map какую-то функцию, которая принимает несколько аргументов, то результат для каждого элемента потенциально может зависеть от всего исходного массива, а не только от самого этого элемента.


Как это невозможна?
Вместо list.map(fun1).map(fun2) можно писать: list.map(x => fun2(fun1(x)))

Нельзя, если fun1 и/или fun2 принимает несколько аргументов.


И что за «операции порядка»? Они не гуглятся.

Отношения порядка, если быть точным.

Речь о другом. Если мы передаём в map какую-то функцию, которая принимает несколько аргументов, то результат для каждого элемента потенциально может зависеть от всего исходного массива, а не только от самого этого элемента.
Но опять же — это не проблема .map'a в JS.
Я изначально отвечал на:
> вы не можете гарантировать, что вызов функции для одного элемента будет зависеть только от этого элемента.
Если функция имеет только один аргумент — то можно гарантировать. Если у нее несколько аргументов, то она и вызывается внутри map с несколькими аргументами. В реальных случаях, если нужно вызвать функцию с несколькими аргументами внутри map — то будет использоваться «обертка» из стрелочной функции.

Нельзя, если fun1 и/или fun2 принимает несколько аргументов.
Но в таком случае у вас будет:
list.map(x => fun1(x)).map(x => fun2(x)) == list.map(x => fun2(fun1(x)))
Где тут «для Javascript — эта оптимизация невозможна»?
[EDIT] Сори, затупил, имелся в виду вызов с несколькими аргументами.
Но тогда прошу привести пример подобного на другом не-функциональном языке программирования.
list.map(x => fun1(x, y)).map(x => fun2(x, y)) == list.map(x => fun2(fun1(x, y), y))
Чем это отличается?

Отношения порядка, если быть точным.
Но я все-равно не понимаю какое отношение это имеет к операторам < и > в JS.
Но опять же — это не проблема .map'a в JS.

Если я правильно понимаю логику изначального автора — именно что проблема. Преобразование, которое в математике называется map, такого поведения иметь не должно.


Но я все-равно не понимаю какое отношение это имеет к операторам < и > в JS.

В том-то и дело, что никакого. А должно иметь, потому что в математике отношения "больше" и "меньше" — это отношения порядка.

Преобразование, которое в математике называется map, такого поведения иметь не должно.

Какого поведения? Надо определиться — мы говорим о математике, или о деталях синтаксиса и реализации. [1, 2, 3].map(x => fun(x)) — чем это не map из математики?

В том-то и дело, что никакого. А должно иметь, потому что в математике отношения «больше» и «меньше» — это отношения порядка.

Можете пожалуйста привести пример на каком-нибудь языке программирования (не функциональном) где эти операторы имеют значение отношения порядка.
Можете пожалуйста привести пример на каком-нибудь языке программирования (не функциональном) где эти операторы имеют значение отношения порядка.

Любой язык с сильной типизацией. Rust, Python, Java, далее везде.

Я видимо правда не знаю, но чем отличаются операторы < >, например в Java и JS?
Только тем что в js можно сравнить разные типы?

Тем, что в JS, в отличие от Java, верна цепочка 12 <= "13" <= "5" <= 12, т.е. нарушается транзитивность.

Но какое отношение это имеет к нашему разговору?
В Java вы такую цепочку вообще не напишете. В Python chained comparison поддерживается только на уровне синтаксического сахара.

Самое прямое. Вы спрашиваете, в каких языках оператор сравнения играет роль отношения порядка. Я отвечаю, что это верно для языков со строгой типизацией. В отличие от JS, где имеется приведённый контрпример. И да, если Вам это принципиально, я могу его переписать так: (12 < "13") && ("13" < "5") && ("5" < 12) — тогда "синтаксический сахар" будет ни при чём, как и должно быть.

Вы спрашиваете, в каких языках оператор сравнения играет роль отношения порядка. Я отвечаю, что это верно для языков со строгой типизацией.
А я вам еще раз повторяю, что то как работают операторы сравнения в разных языках не зависит от того, сильно типизированные они или нет. это все детали имплементации конкретных языков.

Например, сильно-типизированный python (в реализации CPython2) — при сравнении разных типов — сравнивает строки названий их типов (о как!)
Поменяйте местами типы в вашем выражении и python2 вам так же радостно скажет что оно — True.
(12 < «13») and (13 < «5») and (5 < «12»)

ПС большинство языков со строгой типизацией вам вообще не даст сравнить строку с числом.
Поменяйте местами типы в вашем выражении и python2 вам так же радостно скажет что оно — True.
(12 < «13») and (13 < «5») and (5 < «12»)
И именно потому что это — дерьмо собачье в Python3 это исправили. Если бы они, при этом, ещё и работу со строками не поломали… Впрочем в Python 3.7-3.8 всё уже более-менее удобоваримо…

ПС большинство языков со строгой типизацией вам вообще не даст сравнить строку с числом.
Конечно — это их главное преимущество.
По-моему очевидно, что вы в теме весьма поверхностно разбираетесь, при этом почему-то считаете своей обязанностью написать про то как в js все «фигово и не математично..»
А на деле — копнешь чуть глубже и вы начинаете путаться в терминах и уходить от темы.
А на деле — копнешь чуть глубже и вы начинаете путаться в терминах и уходить от темы.
В теме написания говнопрограмм я действительно не разбираюсь. Да и не хочу разбираться.

Вообще показательно, что там где я перепутал термины и написал вместо «отношение порядка» «операции порядка» — вы пошли гуглить, а не указали на путаницу.

Это одна из фундаментальных вещий — но, конечно, знатоках JavaScript она ни к чему.

А четыре арифметических действия не хотите поправить или улучшить? А то там, может, тоже математики налажали.

Или их вы тоже сейчас гуглить пойдёте?
Я учился на английском, поэтому некоторые термины на русском гуглю.
Вместо того чтобы ерничать — вы бы лучше написали чем отличаются операторы <> в python от js, помимо сильной типизации в первом и слабой во втором.
list.map(x => fun1(x, y)).map(x => fun2(x, y)) == list.map(x => fun2(fun1(x, y), y))
Чем это отличается?

Речь, опять же, не об этом (аргумент y у вас берётся из ниоткуда). Пусть у нас функция fun2 принимает три аргумента (а fun1, для простоты, только один). Тогда:


list.map(fun1).map(fun2) — третий аргумент fun2 — преобразованный массив.


list.map((x, i, arr) => fun2(fun1(x), i, arr)) — третий аргумент fun2 — исходный массив.

Речь, опять же, не об этом (аргумент y у вас берётся из ниоткуда)

Речь всю ветку была о том, что в JS .map не как в математике. В математике в map передается по сути только один аргумент — текущий элемент. Все остальные аргументы там могут взяться только «из ниоткуда»
В математике нет никаких дополнительных аргументов в виде индексов и исходных массивов, они добавлены в JS для удобства. Что не делает JS'овский .map «менее математичным»
Что не делает JS'овский .map «менее математичным»
Это делает JS'овский map не имеющим никакого отношения к математике. Всё равно как если бы у вас символом "+" обозначалась операция деления, а сложения в языке вообще не было бы.

Вы бы были готовы работать на таком языке? Я — нет. Вот и с JavaScript такая же история: в тех местах, где его «обойти» нельзя, я, конечно, с ним общаюсь. Но стараюсь делать как можно больше на других, более вменяемых, языках.
Я работаю на js и python, и точно не стал бы говорить что в js все так глупо и неудобно, как «если бы у вас символом „+“ обозначалась операция деления»

Вы бы были готовы работать на таком языке? Я — нет. Вот и с JavaScript такая же история: в тех местах, где его «обойти» нельзя, я, конечно, с ним общаюсь. Но стараюсь делать как можно больше на других, более вменяемых, языках.
А вам подобные топики проходить мимо чувство собственной важности не позволяет?
да, но вы ведь не держите в голове дамп MDN, от API нужна предсказуемость, чего JS не обеспечивает. а с такой логикой как у вас можно вообще безошибочно на чём угодно писать и все языки-api простые :)
от API нужна предсказуемость, чего JS не обеспечивает.
Ему этого не надо. Он не для этого создавался. Не для API предсказуемости.

Ну, а то что стал языком для всего — ну так уж вышло.

Это как вывернутый «наизнанку» глаз зрячего хордового животного, но — «Акцентирование внимания только на одной детали, без попытки найти ей рациональное объяснение в более широком контексте строения глаза как целого и условий его функционирования у конкретного организма, делает аргумент о «нерациональности» скорее эмоциональным, чем научным»

Вспоминая Докинза. (С)
да, но вы ведь не держите в голове дамп MDN, от API нужна предсказуемость, чего JS не обеспечивает.

Еще как обеспечивает. Все методы списков: map/filter/forEach — передают одни и те же аргументы. То что это работает не так как в языке, на котором вы писали раньше — как раз значит что вам надо было, перед тем как начинать программировать, изучить мануалы.
Ну еще, чтобы не держать в голове весь MDN —
можно использовать нормальные ide


то что это работает не так как в языке, на котором вы писали раньше
Проблема в том, что это не работает как в математике, откуда все эти понятия взяты. То есть весь математический аппарат, вокруг этого наработанный, можно забыть.

Так зачем смущать людей, используя названия, которые влекут за собой вполне определённых ожидания — если вы, потом, эти ожидания нарушаете?

Можно использовать нормальные ide<ёblockquote>А можно использовать нормальные языки, которые не требуют, как идиоту, тыкать в каждую букву на экране, чтобы понять что она значит.

И кстати, вы не показали, что ваша IDE покажет на Map'у — что, как раз, гораздо интереснее и важнее.
Проблема в том, что это не работает как в математике, откуда все эти понятия взяты. То есть весь математический аппарат, вокруг этого наработанный, можно забыть.

Так зачем смущать людей, используя названия, которые влекут за собой вполне определённых ожидания — если вы, потом, эти ожидания нарушаете?
Большинство не-функциональных языков работают не «как в математике».
Приведите пример на каком-нибудь Python.

И кстати, вы не показали, что ваша IDE покажет на Map'у — что, как раз, гораздо интереснее и важнее.

Вот что покажет


Тут проблема как раз не в .map, а в том что у parseInt второй аргумент по сути обязательный. Какого фига вы собрались вызывать его без radix'a? А если вам придет строка, например начинающаяся с нуля, и parseInt конвертнет вам ее в какую-нибудь восьмиричную систему. Тоже проблема JS, или все-таки проблема использования функции не по назначению?
['10', '20', '33'].map(Number)

Можно ещё так, слегка попроще получается.

Можно, но если массив будет содержать не только строки или пустые строки, результаты будут отличаться от тех, что отдаст parseInt.
Фишка в том что `map(a => parseInt(a))` в большинстве случаев используют там, где вполне можно обойтись кастом в Number.
В js полно новичков, они задают вопрос про «как конвертнуть строку в число в JS», и получают самый популярный ответ — parseInt. Поэтому лепят его где надо и не надо.
По моему опыту, parseInt — штука весьма специфичная и реально требуется в довольно редких юзкейсах.

Общая рекомендация от Google итд parseInt надо вызывать с redux параметром.

UFO just landed and posted this here
Интересно, а какой умник придумал передачу всего на свете при использовании map?

Функциональные языки программирования обычно передают один параметр — элемент списка (хотя сам список может строиться на основании других структур данных). В данном случае видим крайне «очевидный» подход — а зачем передавать только один параметр? А давайте передадим 3. А почему не 4? А может лучше 5? Не, вот 3 — это самое оно! Но почему? Было бы интересно узнать ответ. Да к тому же для разных структур данных. Например — для множества, где нет индексов. Или для дерева (при использовании соответствующей функции map).

В целом вижу очередное пренебрежение строгоостью. То есть нет явной проверки типов в JS, а потому можно всё — передавать в функцию любое количество параметров, передавать параметры любого типа, вообще не передавать параметры, полная свобода! Но заканчивается такая свобода огромным количеством неявных косяков.

Хотя да, это холиварная тема «строгая типизация против абсолютной вольности».

Да вроде JS не один такой, кто при итерации выводит как минимум два параметра — value и key. В JS при этом третий параметр это вся итерируемая коллекция, что не совсем понятно зачем (ну как непонятно, при .chained подходе может быть удобно, когда итерируемая коллекция неизвестна заранее, например, после .filter), но вроде в каждом итераторе так. В чём здесь вольность — мне непонятно. Особенность? Возможно. Но она известна, задокументирована, и в большинстве своём не вызывает проблем.


Тут вопрос интеграции одних методов с другими (и только для случая передачи функции в качестве аргумента), что, в общем, может быть актуально для любых языков с достаточно сильным стремлением к обратной совместимости, но при этом активно развивающимися.

В чём здесь вольность — мне непонятно.
Вольность в том, что Map — это вещь фундаментальная. Никому ведь не приходит в голову сделать умножение двух элементов таким, чтобы оно, внезапно, передавало в функцию дополнительный аргумент. Хотя есть, конечно, С++ со своим operator++(int);… но там, тоже, это решение считается «не самым удачным» (это если ещё мягко сказать).

Ну так не надо передавать ссылку на сужую функцию куда не просят. Есть же стрелки и обертки.


Индекс в map бывает очень удобен. И это фундаментально и офигенно.

Сужую = чужую, ох уж это. m.habr

А где там сказано что в вызываемую функцию должно передаваться только текущее значение цикла? JS не нарушает фундаментального map, он дополняет его в пределах своей особенности. В JS все встроенные итераторы цикла передают 3 аргумента: значение, индекс и коллекцию. Возьмите forEach, map, filter или любую другую подобную функцию. Так что в данном случае JS делает как раз то что очевидно и привычно для него.
Никакой отсебятины или нарушений стандартов. Всё в соответствии с документацией.
А где там сказано что в вызываемую функцию должно передаваться только текущее значение цикла?
Вы по ссылке-то ходили? Map — это функция высшего порядка, позволяющая применить другую функцию ко всем элементам списка. Ещё представить себе, что если туда передадут функцию с несколькими параметрами, то они будут «прозрачно» переданы из Map в саму вторую функцию (каррирование) можно, то вот передача каких-то «посторонных» элементов — это кошмар.
Ходил. И там нет никаких ограничений на количество и тип параметров у вызываемой функции.
Ваша интерпретация статьи меня не сильно интересует. Я задал конкретный вопрос на который вы не даёте ответа.
Фундаментальность функции не нарушена, она выполняет свои функции так как описано.
Да даже при фильтрации это можно очень удобно использовать.

[1, 1, 2, 2, 2, 3, 4].filter((x, i, a) => a.indexOf(x) === i) // [1, 2, 3, 4]
Жуть какая. Ваши сайты работают слишком быстро и тратят мало памяти? Спросите movl — он научит этот недостаток исправлять!

Какой-нибудь [...new Set([1, 1, 2, 2, 2, 3, 4])] делает то же самое — но обходится без O(N²)…

Ну т.е. вы хотите сказать, что вы никогда не используете второй аргумент (индекс) при использовании .map, .filter и иже с ним? Или может быть вы всегда в callback передаёте функцию так, как это показано в статье и потом на выходе получаете некорректные результаты? Ведь можно же всегда явно обозначить все аргументы, а дальше отправить их уже в нужную функцию.
Я не буду спорить про фундаментальность Map, но как минимум первые два аргумента в JS нахожу крайне полезными.

Давайте так: говорить что я вот вообще никогда-никогда его использовать не буду я не стану. Никогда не говори никогда. Но спомнить случай, когд он был бы полезен я навскидку не могу. Если можете — приведите пример.

Да, разумеется, можно явно обозначить все аргументы, если нам нужно что-то, кроме самих элементов:


vector.iter().enumerate().map(|(index, element)| mapper(element, index))

mapped = map (\(ch, ind) -> mapper ch ind) (zip list [0..])

А если, кроме элементов, больше ничего не нужно — то никто нам ничего лишнего подсовывать не должен.

А Вы хорош! Правда речь вроде шла про использование chaining методов, но никак не про преждевременную оптимизацию.

Речь шла, извините, про преждевременную пессимизацию.

И да, любой код, который имеет сложность, очевидно ассиптотически большую чем оптимальная — я потребую прокомментировать и объяснить почему в данном конкретном случае его можно использовать.

Вы же понимаете, что асимптотическая сложность алгоритма в отрыве от набора данных не является показателем эффективности работы кода? Но в данном случае я согласен с тем, что Ваш пример обычно будет работать быстрее, по множеству причин. Вот только утверждение, что там сложность меньше чем O(n²), по-хорошему, нуждается в доказательствах. Причем если мы говорим про язык, а не про конкретные реализации, то и доказательством должно являться требование к реализации структуры Set в спецификации языка.


И раз уж Вы прям затребовали комментариев о причинах возможного использования подобного кода, то причины могут заключаться в удобстве этого использования, о чем я заявил изначально. Chaining методы удобны тем, что их можно писать друг за другом, а значит мой пример предполагал возможность выбора уникальных значений списка, без разрыва цепочки преобразований. И именно на этом я делаю акцент еще раз.


Выбирать, что в каждом конкретном случае выгоднее: оптимизация, или скорость разработки, или читаемость кода, или любой другой параметр, — это вопрос каждого конкретного случая. Ну только если у Вас вдруг не затерялся где-то рецепт серебряной пули. Потому считаю Ваши выпады предвзятыми и не претендующими хоть на какую-то объективность. В связи с этим откланиваюсь.

Вы же понимаете, что асимптотическая сложность алгоритма в отрыве от набора данных не является показателем эффективности работы кода?
Не является. Но на практике ситуация, когда рассчитывали на 5 элементов, а получили 50 — более, чем типична. Джефф Дин пропагандирует подход 10x: если вы считаете, что ваш код будет обрабатывать, скажем, сто элементов — то писать его нужно так, чтобы тысяч никого не напрягла. А вот если потребуется миллион — тут уже можно и переписать что-то.

Вот только утверждение, что там сложность меньше чем O(n²), по-хорошему, нуждается в доказательствах.
Нет, не нужно. Set предназначен для той операции, которую вы хотите проделать. Если он реализован не оптимально — то это, обычно, уже не ваша проблема.

Да, иногда проколы встречаются и в стандартной библиотеке обнаруживаются странные вещи (типа сортировки, которая можете вырождаться в O(n²)), но их, как раз, можно «разово» пофиксить, написав свою реализацию. 100500 мест, где вы сами, своими руками, создали себе O(n²) — можно пофиксить только путём переписывания.

И раз уж Вы прям затребовали комментариев о причинах возможного использования подобного кода, то причины могут заключаться в удобстве этого использования, о чем я заявил изначально.
И именно поэтому я требую не устного объяснения, а комментария в коде. Подробного. Строчек на 10. Со ссылками на документы, которые гарантируют нам, что в данном конкретном случае O(n²) нас устраивает. Если подобное описание написать проще, чем всё сделать оптимально — ну Ok, возможно, в данном конкретном случае этот варинт и подходит. Но в большинстве случаев эта экономия — копеечная, а последующие тормоза — вполне реальны.

Chaining методы удобны тем, что их можно писать друг за другом, а значит мой пример предполагал возможность выбора уникальных значений списка, без разрыва цепочки преобразований. И именно на этом я делаю акцент еще раз.
А я ещё раз сделаю акцент на том, что вы экономите несколько минут разработчика один раз, а страдать потом приходится пользователям годами.

Если вы пишите проекты «в корзину» с подходом «после нас хоть потоп»… ну это — ваш выбор. Я в таких развлечениях стараюсь не участвовать.

Выбирать, что в каждом конкретном случае выгоднее: оптимизация, или скорость разработки, или читаемость кода, или любой другой параметр, — это вопрос каждого конкретного случая.
Конечно. Вопрос в дефолте. Если у вас дефолт — писать «тяп-ляп», то ваши программы всегда будут тормозить. Если дефолт — писать аккуратно — не будут. И на практике написать ассмптотически оптимально — почти всегда не в 10 раз сложнее, чем «тяп-ляп»…

Очередной пример, показывающий то, что если что-то завозят в JS, то только наполовину: map, reduce есть, а groupBy из коробки — нет.

Блин вот никогда мне не жалко было ресурсов при обработке массива из 7 значений. Особенно, если есть требование о поддержки дерьма мамонта от мелкософт. И лучше использовать O(n**2), чем думать как транспайлер справится с Set.


Оптимизация и так дешевых фрагментов один из способов ни хрена полезного не делать, но чувствовать свою нужность

Оптимизация и так дешевых фрагментов один из способов ни хрена полезного не делать, но чувствовать свою нужность
Откуда вы знаете что эти фрагменты будут дешёвыми? Откуда вы знаете что там всегда будет 7 значений?

Правило-то простое: не пишите, без должной причины, код, который имеет ассимтотически неоптимальную сложность — и вам не придётся его оптимизировать.

И лучше использовать O(n**2), чем думать как транспайлер справится с Set.
Зачем транспайлеру как-то особо справляться с Set, если он поддерживается во всех современных браузерах? И я лучше напишу код, который будет нормально работать на всех современных браузерах, чем буду думать о MS IE 9.

Вообще странная идея: использовать стерлочные функции и при этом рефлексировать по поводу Map и Set.
Но почему? Было бы интересно узнать ответ.
Потому что это удобно.
Функциональные языки программирования обычно передают один параметр
JS — не функциональный ЯП.
А ещё было бы удобно передавать десяток дополнительных параметров. Но не передают ведь. Неудобно!

Есть типизированный подход и есть брейнфак. Вот JS — это по сути брейнфак, потому что без зубрёжки толстенной спецификации — всё будет неочевидным и непонятным. Преимущество типизированных языков здесь очевидно — не надо зубрить столько УГ.
['1', '7', '11'].map(v => +v);

Но есть и отличия с parseInt
['1', '7', '11', null, undefined, '12s3'].map(v => parseInt(v,10));
// [1, 7, 11, NaN, NaN, 12]
['1', '7', '11', null, undefined, '12s3'].map(v => +v);
// [1, 7, 11, 0, NaN, NaN]

Кто-от обязательно этот вопрос включит в собеседование. Хорошо это или плохо?
UFO just landed and posted this here
Я бы для обьяснения эффекта лаконично переписал

['1', '7', '11'].map((v, i, iteratee)=>parseInt(v, i));
UFO just landed and posted this here
Так еще лучше, спасибо.
Только это не правильно. parseInt в качестве второго аргумента принимает основание системы счисления!
UFO just landed and posted this here
UFO just landed and posted this here

Я очень надеюсь, что это сейчас постирония была...

Нет, он прав. Но VBScript «не взлетел». Кроме всего прочего это был стандарт, поддерживаемый одним-единственным браузером — и даже там это была урезанная версия VB, увы.
Статья занятная и полезная, но посыл первого абзаца ложный. Ничего странного, всё работает как задумано и как должно.
UFO just landed and posted this here
Но ведь radix там указан при вызове… бессмысленный — но указан.
Ага, а [1, 2, 5, 10].sort() выдает [1, 10, 2, 5] по той же самой причине — по которой нормальные люди на этом языке не пишут и как настоящий язык его не воспринимают.
Вот бы можно было зайти на MDN и узнать, что оказывается, сортировку можно (нужно) выполнять по правилам собственной функции, а по-умолчанию (без аргументов) сравнение идет с приведением значений к строкам, по их UTF-кодам. Но кто же читает инструкции документацию?!
В последние годы, на фоне популярности JS стало откровенно модно критиковать его. Критика — это здорово, когда она по делу, а не ради хохмы. Пример из статьи не кажется жизнеспособным. Согласен с i360u

Внезапно:
> ['1', '7', '11'].map(i => parseInt(i))
< (3) [1, 7, 11]
В последние годы

Мне кажется, JS критикуют с момента его появления :)

И для этого нужна целая статья? Люди уже совсем отупели, что не могу просто mdn или спеку почитать?
Спасибо за пост, довольно интересно, и я думаю, что я должен включить это в интервью
На мой взгляд — статья дурацкая. Да, в JS `map` передает несколько аргументов — это нормально. То что у parseInt несколько аргументов — тожe нормально.
Проблема в том, что parseInt используют не по назначению. В основном чтобы «преобразовать строку в число», но проблема в том, что Int — это не просто число, это Integer. Просто загуглите «parseInt not working with decimal» чтобы понять что куча новичков использует его, даже не понимая значения этой функции.
parseInt, лично по моему опыту — очень узкоспециализированная штука, надо просто вместо него в туториалах использовать `Number(string)`

Дык parseInt и надо использовать, если мы хотим получить целое число, а не просто число.
И чаще всего хочется видеть именно целое.

чаще всего хочется видеть именно целое

Приведите хоть один пример, который встречается условно часто.

Обычная ситуация — вы ожидаете числа, а апи присылает строки. Вам не нужны конкретно целые числа, a просто нужно сделать числа из ответа апи.
поэтому и придумывают языки, которые умеют в JS, например, ClojureScript:
(map js/parseInt ["1", "7", "11"])

=> (1 7 11)
Спустя восемь лет нас удивляют всё те же вещи )

я в своё время придумал на основе этой чуть более хитрую задачу — объяснить почему этот «фикс» не сработал для нулевого элемента массива
['1', '7', '11', '19', '29', '33'].map(parseInt.bind(null, 10))
//[NaN, 7, 11, 19, 29, 33]
Спустя восемь лет нас удивляют всё те же вещи )
Дерьмо остаётся дерьмом и через восемь лет и через восемьдесят.

P.S. Ответ на вопрос с bind становится резко понятен при замене '33' на '333', например…
Sign up to leave a comment.

Articles