2

я следующие функциитип Scala проверки ошибок компиляции

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

    def concat[A](l: List[List[A]]): List[A] 

Я хотел бы реализовать это один

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

Теперь я знаю, что правильное решение (так что это не вопрос)

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

Но когда я пытался решить ее, я впервые попробовал с (я забыл Concat)

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

// compilation output 
[error] found : A => fpinscala.datastructures.List[B] 
[error] required: A => B 
[error]  map(l)(f) 

Я не могу понять эту ошибку, потому что выглядит как оценки map(l)(f) неправильно, но это не так, то возвращаемое значение функции flatMap, что является неправильным.

Фактически, если разложить одну и ту же реализацию в двух строках кода, мы увидим, что компилятор Scala жалуется на другую ошибку - на самом деле это ошибка, которую я ожидал и в предыдущем коде.

def flatMap[A,B](l: List[A])(f: A => List[B]): List[B] = { 
    var result = map(l)(f) 
    result 
    } 

// compilation output 
[error] found : fpinscala.datastructures.List[fpinscala.datastructures.List[B]] 
[error] required: fpinscala.datastructures.List[B] 
[error]  result 

Может кто-нибудь объяснить мне, почему компиляция первой попытки кода дается различного рода ошибки, что второй один?

+0

Согласен, но это не объясняет, почему компилятор Scala жалуется на него в первом коде, но не во втором. Единственное различие заключается в том, что во втором я сохраняю результат в переменной, но вызов функции карты тот же. –

ответ

5

Вы должны знать, как проверяют типы Scala. Он использует Unification algorithm. Простыми словами это означает, что он следует принципу сверху/вниз.

Напомним, что map имеет тип List[U] => (U => V) => List[V] (независимо от типа U и V). В первом неправильном коде вы написали, что ваша функция возвращает List[B]. Поэтому вы скажете Scala, что map(l)(f) должен быть типа List[B]. Теперь вы распространяете константы сверху/снизу. Для map(l)(f) должно быть типа List[B], вам необходимо иметь l типа List[A] (независимо от того, A is) и f типа A => B. Таким образом, компилятор жалуется, потому что вы дали f типа A => list[B].

Если второй неправильный код, вы уже правильно вычислили result типа List[List[B]]. Однако во второй строке вы пытаетесь вернуть result, но ваша функция объявлена ​​для возврата list[B]. Отсюда сообщение об ошибке.

+0

Я понимаю, что вы сказали, но почему ошибка первого кода не применима ко второму? Я все еще не вижу разницы между «map (l) (f)» и «var result = map (l) (f)». –

+1

Поскольку вы не указали какой-либо тип для 'результата' на этом этапе. Поэтому вполне нормально определять его таким образом, что тип «List [List [B]]». Проблема возникает, когда вы пытаетесь вернуть ее. Если вы пишете 'var result: List [B] = map (l) (f)', тогда вы должны получить ту же ошибку. – hivert

+0

Совершенно очевидно ошибка второго кода, и это не главное. Вопрос в том, почему оценка первой карты неверна для компилятора, а вторая - нет. На императивном языке ожидаемая ошибка будет одинаковой (не имеет значения, если вы сохранили результат в нескольких переменных, прежде чем возвращать его), в этом случае ошибка, которая поднимает второй код. –

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