У меня нет докторской степени, ни какой-либо другой степени ни в CS, ни в математике, ни вообще в какой-либо другой области. У меня нет опыта работы со Scala и других подобных языков. У меня нет опыта даже с дистанционно сопоставимыми системами типов. Фактически, единственный язык, который у меня есть больше, чем просто поверхностное знание, о котором даже есть система типов, - это Паскаль, не совсем известный своей сложной системой типов. (Хотя это действительно есть типы диапазонов, которые AFAIK в значительной степени никакой другой язык имеет, но это не совсем уместным здесь.) Остальные три языка я знаю, BASIC, Smalltalk и Руби, ни один из которых даже есть система типа.
И все же у меня нет проблем с пониманием подписи map
функции, которую вы опубликовали. Мне кажется, что это та же подпись, что map
и на любом другом языке, который я когда-либо видел. Разница в том, что эта версия более общая. Это больше похоже на C ++ STL, чем, скажем, на Haskell. В частности, он абстрагируется от конкретного типа коллекции, требуя только, чтобы аргумент был IterableLike
, и также абстрагируется от конкретного возвращаемого типа, только требуя, чтобы существовала неявная функция преобразования, которая может построить что-то из этой совокупности значений результата. Да, это довольно сложно, но на самом деле это всего лишь выражение общей парадигмы общего программирования: не предполагайте ничего, что вам на самом деле не нужно.
В этом случае на map
самом деле не нужно, чтобы коллекция была списком, или была упорядочена, или сортировалась, или что-то в этом роде. Единственное, что map
волнует, - это то, что он может получить доступ ко всем элементам коллекции, один за другим, но в произвольном порядке. И ему не нужно знать, что такое итоговая коллекция, нужно только знать, как ее собрать. Итак, это то, что требует его сигнатура типа.
Итак, вместо
map :: (a → b) → [a] → [b]
это традиционная сигнатура типа map
, она обобщена так, что не требует конкретной, List
а скорее просто IterableLike
структуры данных
map :: (IterableLike i, IterableLike j) ⇒ (a → b) → i → j
который затем дополнительно обобщается, требуя только наличия функции, которая может преобразовать результат в любую структуру данных, которую хочет пользователь:
map :: IterableLike i ⇒ (a → b) → i → ([b] → c) → c
Я признаю, что синтаксис немного более грубый, но семантика та же. В основном, это начинается с
def map[B](f: (A) ⇒ B): List[B]
которая является традиционной подписью для map
. (Обратите внимание, что из-за объектно-ориентированной природы Scala входной параметр списка исчезает, потому что теперь это неявный параметр-приемник, который есть у каждого метода в ОО-системе с одной диспетчеризацией.) Затем он обобщается из конкретного List
в более общий.IterableLike
def map[B](f: (A) ⇒ B): IterableLike[B]
Теперь он заменяет IterableLike
коллекцию результатов функцией, которая производит практически что угодно.
def map[B, That](f: A ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That
Что я действительно считаю , это не что трудно понять. На самом деле вам нужна только пара интеллектуальных инструментов:
- Вы должны знать (примерно), что
map
есть. Признаю, что если вы дадите только сигнатуру типа без имени метода, выяснить, что происходит, будет намного сложнее. Но поскольку вы уже знаете, что map
предполагается делать, и знаете, какой должна быть его сигнатура типа, вы можете быстро отсканировать сигнатуру и сосредоточиться на аномалиях, например: «Почему для map
аргументов используются две функции, а не одна?»
- Вы должны быть в состоянии действительно прочитать сигнатуру типа. Но даже если вы никогда раньше не видели Scala, это должно быть довольно просто, поскольку на самом деле это просто смесь синтаксисов типов, которые вы уже знаете из других языков: VB.NET использует квадратные скобки для параметрического полиморфизма и использует стрелку для обозначения возвращаемый тип и двоеточие для разделения имени и типа, на самом деле является нормой.
- Вы должны примерно знать, что такое общее программирование. (Который не , что трудно понять, так как это в основном все прописано в названии: это буквально только программирование в общем виде).
Ни один из этих трех не должен вызывать серьезную головную боль у любого профессионального или даже программиста-любителя. map
была стандартной функцией почти во всех языках, разработанных за последние 50 лет, тот факт, что разные языки имеют разный синтаксис, должен быть очевиден для всех, кто разработал веб-сайт с HTML и CSS, и вы не можете подписаться даже на дистанционное программирование связанный список рассылки без какого-либо раздражающего фаната C ++ из церкви Святого Степанова, объясняющего достоинства общего программирования.
Да, Scala является сложным. Да, Scala имеет одну из самых сложных систем типов, известных человеку, конкурирующую и даже превосходящую языки, такие как Haskell, Miranda, Clean или Cyclone. Но если бы сложность была аргументом против успеха языка программирования, C ++ давно бы умер, и мы все писали бы Scheme. Существует множество причин, по которым Scala, скорее всего, не будет успешным, но тот факт, что программисты не могут потрудиться включить свои мозги перед тем, как сесть перед клавиатурой, вероятно, не будет главной.