2015-11-28 4 views
3

Для задания кодирования для школы я должен делать материал с планшетами, но я абсолютно не знаю, что он делает, и я прочитал пару страниц в Интернете и прочитал в своем учебнике, но у меня все еще нет истинного понимания того, что он делает. Я знаю, что делает карта, но по какой-то причине мне трудно обернуть голову вокруг плоской карты. Может ли кто-нибудь помочь? Благодарю.Что делает flatMap точно?

Просто добавьте дополнительную информацию - когда я смотрю примеры в Интернете, я вижу, как flatmap возвращает что-то отличное от карты. Но что такое плоская карта, когда ее когда-то называют? Как работает планшет? Что он делает, прежде чем он вернет результат?

+1

Это не вводите StackOverflow в Вопросительный – UserNotFoundException

+0

flatmap = карта + расплющить – 757071

+0

Какой вопрос тогда? –

ответ

4

ФУНКТОРЫ определить карту, которые имеют тип

trait Functor[F[_]] { 
    def map[A, B](f: A => B)(v: F[A]): F[B] 
} 

Монады функторы, которые поддерживают две дополнительные операции:

trait Monad[M[_]] extends Functor[M] { 
    def pure[A](v: A): M[A] 
    def join[A](m: M[M[A]]): M[A] 
} 

Регистрация сглаживает иерархические значения, например, если m является List то join имеет типа

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

Если у вас есть монады m и вы map над ним, что произойдет, если b тот же монадический типа? Например:

def replicate[A](i: Int, value: A): List[A] = ??? 
val f = new Functor[List] { 
    def map[A, B](f: A => B)(v: List[A]) = v.map(f) 
} 

затем

f.map(x => replicate(x, x))(List(1,2,3)) == List(List(1), List(2,2), List(3,3,3)) 

Это имеет тип List[List[Int]] а вход является List[Int]. Для цепочки операций довольно часто требуется, чтобы каждый шаг возвращал один и тот же тип ввода. Поскольку List также могут быть сделаны в монады, вы можете легко создать такой список, используя join:

listMonad.join(List(List(1), List(2,2), List(3,3,3))) == List(1,2,2,3,3,3) 

Теперь вы можете написать функцию, чтобы объединить эти две операции в одну:

trait Monad[M] { 
    def flatMap[A, B](f: A => M[B])(m: M[A]): M[B] = join(map(f)(m)) 
} 

то вы можете просто сделать:

listMonad.flatMap(List(1,2,3), x => replicate(x, x)) == List(1,2,2,3,3,3) 

Именно то, что делает flatMap зависит от типа монады конструктора M (List в этом примере), поскольку он зависит от map и join.

+0

Я не могу представить этот разговор Монады помогут оригинальному плакату. – Alper

+0

@alper - Как вы можете объяснить «flatMap», не говоря о монадах? Тот факт, что они приняли этот ответ, указывает на то, что они нашли это полезным. – Lee

+0

Я думаю, что это бесполезно обскурантист, так как сами монады тоже нигде не объясняются. – Alper

4

Вот аналогия.

Представьте, что у вас есть большая сумка, заполненная ваучерами для покупок на картонные коробки. Если у вас есть функция, которая «использует ваучер, чтобы купить коробку с яйцами», и вы вызвали bigBagOfVouchers.map(buyCartonOfEggs), у вас будет пакет картонных коробок с яйцами.

Однако, если вы позвонили bigBagOfVouchers.flatMap(buyCartonOfEggs), у вас будет мешок с яйцами - без картонных коробок.

flatMap сглаживает результат на один уровень. Что могло быть Bag[Carton[Egg]] сейчас Bag[Egg].

+1

Правильно ли это? Я всегда думал, что «flatMap» требует, чтобы «внутренняя» монада была точно такой же, как «внешняя» монада. Хотя, я думаю, вы могли бы сказать, что это сработает, если и 'Bag', и' Carton' будут 'Iterable'. – melston

+0

в основном .flatMap - это ничего, кроме .map (x => something (x)). Flatten. Действительно ли я в своем предположении? – Rakshith

+0

Правильно. Хотя 'flatten' не существовало до v2.8 http://stackoverflow.com/questions/2895069/how-to-flatten-list-of-options-using-higher-order-functions – Synesso

0

В реактивном программировании часто вступают в ситуацию, в которой вам нужно использовать flatMap конвертировать Future [Future [Список]] в Future [Список]. Например, у вас есть две функции: get Пользователи из базы данных и процесс извлеченные пользователи; и оба возвращаются Будущее [Список [Пользователь]]. Если применить карту к получить и процесс, результат будет Future [Future [Список [Пользователь]]], который не имеет никакого смысла. Вместо этого, вы должны использовать flatMap:

def main(): Future[List[User]] = getUsers flatMap processUsers  
def getUsers: Future[List[User]] 
def processUsers(users: List[User]): Future[List[User]]