Разница ч/б Method[Int]() и Method() в scala?

Увидев сигнатуру метода карты в scala как

def map[A, B](l: List[A])(f: A => B): List[B] = ???

мое непрофессиональное понимание [A, B] выше заключается в том, что они сигнализируют методу, что мы будем работать исключительно с универсальными типами A и B в определенном методе.

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

def addCorresponding[Int](l1: List[Int],
                        l2: List[Int]): List[Int] =
  (l1, l2) match {
      case (_, Nil) => Nil
      case (Nil, _) => Nil
      case (x::xs, y::ys) => {
          List((x + y)) ++ addCorresponding(xs, ys)
      }
}

но получите эту ошибку при добавлении элементов в последнем совпадении: Найдено несоответствие типа: Int Требуется: String

Удаление [Int] из подписи mehtod исправляет эту ошибку.

Я уверен, что в моем понимании универсальных типов и того, когда их добавлять в сигнатуру метода, есть пробелы. Я был бы признателен, если бы кто-нибудь провел меня через это и объяснил, почему метод addCorresponding с ошибками [Int] не работает, но отлично работает без него?

Параметр типа — это, по сути, параметр. Например, когда вы делаете def plusFive(x: Int): Int = x + 5, что такое x? Все, что передается в функцию. Это не 1, и не 0, и даже не 5 и не 3, это просто параметр. Таким образом, в первом примере A и B являются параметрами для типов, что означает, что сейчас они не являются каким-либо правильным типом, они будут заполнены компилятором при вызове. Во втором примере вы хотите, чтобы оба списка имели тип Int, так как вы хотите суммировать элементы, это то, что вы можете делать только с Ints, поэтому не нужно добавлять параметр типа.

Luis Miguel Mejía Suárez 25.12.2020 23:56

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

Luis Miguel Mejía Suárez 25.12.2020 23:57

Ах, теперь это имеет смысл. Спасибо за Ваш ответ.

rghv404 26.12.2020 04:53

Есть очень похожий вопрос: stackoverflow.com/q/65322171/2359227

Tomer Shetah 27.12.2020 11:22

Кстати, почему вы не используете zip? Он делает именно то, что вы пытаетесь сделать. scastie.scala-lang.org/yYCapPvmSgWWE467QRh4ZQ

Tomer Shetah 27.12.2020 11:27

@TomerShetah Спасибо, что поделились ссылками. Я только начал изучать Scala по Красной книге и застрял в реализации zip самостоятельно в соответствии с одним из упражнений.

rghv404 27.12.2020 19:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
97
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Общий метод (с параметром типа) будет

def addCorresponding[A](l1: List[A], l2: List[A]): List[A]

или, если списки могут иметь разные типы элементов

def addCorresponding[A, B, C](l1: List[A], l2: List[B]): List[C]

Если вы реализуете метод, который работает с конкретным типом Int, то ваш метод больше не является универсальным:

def addCorresponding(l1: List[Int], l2: List[Int]): List[Int]

Другими словами, вы применяете конкретный тип Int здесь к List[_] вместо параметра абстрактного типа. Если вы пишете

def addCorresponding[Int](l1: List[Int], l2: List[Int]): List[Int]

затем вы «затеняете» конкретный тип Int параметром абстрактного типа Int, который имеет то же имя; но технически вы пишете общий метод

def addCorresponding[XXX](l1: List[XXX], l2: List[XXX]): List[XXX]

Если вы хотите, чтобы ваш метод был универсальным, но выполнял определенные операции с элементами типа A, вам может понадобиться класс типа, например, Numeric для арифметического добавления элементов.

def addCorresponding[A](l1: List[A],
                        l2: List[A])(implicit num: Numeric[A]): List[A] =
  (l1, l2) match {
    case (_, Nil) => Nil
    case (Nil, _) => Nil
    case (x::xs, y::ys) =>
      List((num.plus(x, y))) ++ addCorresponding(xs, ys)
  }

Спасибо за подробный ответ и общую реализацию.

rghv404 02.01.2021 20:43

Другие вопросы по теме