2015-02-22 3 views
2

Когда я пишу функцию вроде def foo[A,B], что именно означает [A,B]? Я знаю, что это Polymorphic Method; но когда вы используете foo [A] против foo [A,B]?Что именно означает def foo [A, B]? Тип затенения

Вот пример, когда я не понимаю разницы. Эта функция составляет:

def map[B](f: A => B): Stream[B] =            
    foldRight(empty[B])((h,t) => cons(f(h), t)) 

Принимая во внимание, что этот не компилируется. Я не понимаю, почему A не требуется, ведь A ссылается на f: A => B:

def map[A,B](f: A => B): Stream[B] =            
    foldRight(empty[B])((h,t) => cons(f(h), t)) 

[error] ..../Stream.scala:61: type mismatch; 
[error] found : h.type (with underlying type A) 
[error] required: A 
[error]  foldRight(empty[B])((h,t) => cons(f(h), t)) 

(это от одного из FP in Scala упражнений)

Добавление

Прочитав ответы, я добавляю некоторый контекст, чтобы помочь будущим читателям. Функция определена внутри признака:

trait Stream[+A] { 
    ... 
    def map[B](f: A => B):Stream[B] = 
    foldRight(empty[B])((h,t) => cons(f(h), t)) 
    ... 
} 

Так что ошибка была вызвана типа затенения, но видеть @ отличный ответ acjay в поле ниже.

Googling scala type shadowing не дает прямого определения ни в одном из документов scala, что интересно, потому что, как @travisbrown говорит ниже, это «один из самых распространенных источников замешательства новичка, который я видел». Здесь обсуждается: Why does Scala support shadow variables?

+0

Где вы видели метод «map»? Если он является членом класса, сам класс может определить параметр типа 'A' ​​ – mucaho

+0

Вы определяете' map' в классе, который определяет 'Stream [A]' (я предполагаю), поэтому абстрактный тип 'A' является уже определен и «map» должен иметь абстрактное имя для типа результата функции. – fedragon

+0

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

ответ

4

В первом примере есть только один параметр типа, потому что это не функция изолированно, это метод в классе Stream[A], который объявляет параметр первого типа. Примерно так:

class Stream[A] { 
    // ... 

    def map[B](f: A => B): Stream[B] =            
    foldRight(empty[B])((h,t) => cons(f(h), t)) 

    // ... 
} 

Таким образом, вы получите A от окружающего области видимости класса. Предположим, что вместо этого вы сделали map метод на компаньонном объекте. В этом случае объект компаньон не имеет параметр типа, так что вы должны определить оба параметра по методу:

class Stream[A] { 
    // ... methods, with foldRight, but no `map` 
} 

object Stream { 
    // ... 

    def map[A, B](stream: Stream[A])(f: A => B): Stream[B] =            
    stream.foldRight(empty[B])((h,t) => cons(f(h), t)) 

    // ... 
} 

Этот второй вариант будет использоваться несколько иначе. Вы бы сказали Stream.map(myStream)(myMappingFunction) вместо myStream.map(myMappingFunction). Оба варианта совершенно верны, но, вероятно, более идиоматично применять метод в классе.

Итак, чтобы ответить на ваш вопрос, вы используете несколько типов параметров для метода, когда два или более аргументов и/или тип возвращаемого типа должны быть общими.Вы также можете использовать два параметра типа для классов, а также, как (без учета дисперсии):

Тип Map[A, B] - A является тип ключа и B тип значения

Тип Tuple2[A, B] (более известный как (A, B)) - A типа 1-го элемента, B типа 2-го элемента

Тип Function1[A, B] (более известный как A => B) - A типа аргумента, B является типом возвращаемого

... и прочее.

+0

Большое спасибо @acjay за отличный ответ, теперь я понимаю. Я добавлю добавление к моему вопросу, чтобы предоставить некоторый контекст. –

Смежные вопросы