2011-12-22 3 views
3

Я изучаю scala, и этот вопрос может быть глупым, но ... почему?scala: ошибка несоответствия типа - найден T, обязательно Строка

Например, это нормально:

def matchList(ls: List[Int]): List[Int] = ls match { 
    case 1 :: rest => rest 
    case a :: b :: rest => (a + b) :: rest 
    case _ => ls 
} 

matchList: (ls: List[Int])List[Int] 

Но функция с параметром типа не компилируется:

def matchList[T](ls: List[T]): List[T] = ls match { 
    case 1 :: rest => rest 
    case a :: b :: rest => (a + b) :: rest 
    case _ => ls 
} 

<console>:10: error: type mismatch; 
found : T 
required: String 
    case a :: b :: rest => (a + b) :: rest 

Почему?

ответ

8

Для любого типа T операция T + T не имеет никакого смысла. (Не все виды поддержки +? Нет. Подумайте о добавлении двух собак или двух человек.)

В вашем случае оператор конкатенации становится вызывается (добавлено через any2stringadd сутенера), чей возвращаемый тип (очевидно) String. Отсюда сообщение об ошибке.

Что вам нужно, это способ указать, что тип T должен поддерживать операцию, где вы объединить два значение типа T, чтобы получить новое значение типа T.Scalaz's Semigroup подходит для счета отлично.

следующие работы:

def matchList[T : Semigroup](ls: List[T]): List[T] = ls match { 
    case 1 :: rest => rest 
    case a :: b :: rest => (a |+| b) :: rest // |+| is a generic 'combining' operator 
    case _ => ls 
} 
+0

Обязательно ли он, чтобы операция была ассоциативной? – huitseeker

+0

Он этого не уточнил. И я не могу придумать случай, когда ассоциативность повредит его проблеме. – missingfaktor

+0

Вы правы, это не будет: 'matchList'combines не более двух элементов, поэтому ассоциативность не имеет значения. 'twas просто напоминание. Полугруппа имеет более крупную спецификацию, чем просто операцию типа T -> T -> T'. :) – huitseeker

3

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

+1

@ путать демона: есть 'any2string' заложенная в Scala, который индуцирует преобразование в этом дело. Нет необходимости в неявном преобразовании в конкретном случае «Int». – Debilski

+0

@ confused-demon проблема здесь в том, что Scala не знает, что 'T' будет' Int', поэтому он не может работать с этим. – nonVirtualThunk

+0

Извините, я еще не зашел так глубоко. Является ли 'any2string implicit' означать' если тип неизвестен, в этом случае он преобразуется в строку'? И, чтобы быть полным, как функция параметризованного типа может быть реализована для работы с Int, Double и String, например? – dmitry

2

Во втором примере, ваш a, b переменных заявляемого типа T не являются конвертируемыми в String, который является обязательным типом аргумента +, выводится из вашей программы (т.е. вид применяется к типу аргументов + при отсутствии какой-либо другой информации).

В первом примере вывод может угадывать правильную функцию + для применения, считая, что она принимает в качестве аргументов тип элементов списка, и что, к счастью, вы упомянули в объявлении типа, что тип этих элементов Int. Попробуйте ввести

"1"+2 

1 + 2 

... в REPL и посмотреть, что делает Scala. Затем прочитайте около views.

Теперь, я предполагаю, что с помощью этого параметра типа T выше, вы пытаетесь написать функцию, которая работает с любого числового типа, не так ли? В этом случае вы можете работать с чертой Numeric.Я дам вам прочитать на implicits, прежде чем предлагать следующее:

def matchList[T](ls: List[T])(implicit n:Numeric[T]): List[T] = { 
    import n.mkNumericOps 
    ls match { 
    case 1 :: rest => rest 
    case a :: b :: rest => (a + b) :: rest 
    case _ => ls 
}} 

Вы получаете:

matchList(List(1,2,3)) 
res2: List[Int] = List(2, 3) 
matchList(List(2,3,4)) 
res4: List[Int] = List(5, 4) 
matchList(List(2.0,3.0,4.0)) 
res5: List[Double] = List(5.0, 4.0) 
Смежные вопросы