TL; DR doğrudan son örneğe gider
Deneyeceğim ve özetleyeceğim.
Tanımlar
for
Anlama birleştirmek için bir sözdizimi kısayoldur flatMap
ve map
okumak ve yaklaşık sebebi kolay bir şekilde.
İşleri biraz basitleştirelim ve class
yukarıda bahsedilen her iki yöntemi sağlayan her birinin a olarak adlandırılabileceğini monad
ve iç tipi ile M[A]
a anlamına gelmek için sembolü kullanacağımızı varsayalım .monad
A
Örnekler
Yaygın olarak görülen bazı monadlar şunları içerir:
List[String]
nerede
M[X] = List[X]
A = String
Option[Int]
nerede
Future[String => Boolean]
nerede
M[X] = Future[X]
A = (String => Boolean)
harita ve düz harita
Genel bir monadda tanımlanmıştır M[A]
def map(f: A => B): M[B]
def flatMap(f: A => M[B]): M[B]
Örneğin
val list = List("neo", "smith", "trinity")
val f: String => List[Int] = s => s.map(_.toInt).toList
list map f
>> List(List(110, 101, 111), List(115, 109, 105, 116, 104), List(116, 114, 105, 110, 105, 116, 121))
list flatMap f
>> List(110, 101, 111, 115, 109, 105, 116, 104, 116, 114, 105, 110, 105, 116, 121)
ifade için
<-
Sembolü kullanan ifadedeki her satır, flatMap
bir sonuç map
çağrısına çevrilen son satır haricinde , sol taraftaki "bağlı sembol" argüman işlevine parametre olarak aktarılır (ne daha önce aradık f: A => M[B]
):
for {
bound <- list
out <- f(bound)
} yield out
list.flatMap { bound =>
f(bound).map { out =>
out
}
}
list.flatMap { bound =>
f(bound)
}
list flatMap f
Yalnızca bir ifadeye sahip <-
bir map
ifade, bağımsız değişken olarak iletilen ifade ile bir çağrıya dönüştürülür :
for {
bound <- list
} yield f(bound)
list.map { bound =>
f(bound)
}
list map f
Şimdi konuya
Görebileceğiniz gibi, map
işlem orijinalin "şeklini" korur monad
, bu nedenle yield
ifade için de aynı şey olur : a , içindeki işlem tarafından dönüştürülen içerik ile a olarak List
kalır .List
yield
Diğer yandan, içindeki her cilt çizgisi, tek bir "dış şekli" korumak için "düzleştirilmesi" gereken for
ardışık bir bileşimdir monads
.
Bir an için her iç bağlantının bir map
çağrıya çevrildiğini , ancak sağ elin aynı A => M[B]
işlev olduğunu, M[M[B]]
anlamadaki her satır için bir ile sonuçlanacağını varsayalım .
Tüm for
sözdiziminin amacı, ardışık monadik işlemlerin (yani, "monadik bir şekilde" bir değeri "yükselten" işlemler) birleştirilmesini, muhtemelen bir nihai dönüşümü gerçekleştiren bir A => M[B]
son map
işlemin eklenmesiyle kolayca "düzleştirmek" tir .
Umarım bu, mekanik bir şekilde uygulanan çeviri seçiminin arkasındaki mantığı açıklar, yani n
flatMap
tek bir map
çağrı ile sonuçlanan iç içe aramalar .
Yapmacık bir açıklayıcı örnek Sözdiziminin
anlamlılığını göstermek anlamına gelirfor
case class Customer(value: Int)
case class Consultant(portfolio: List[Customer])
case class Branch(consultants: List[Consultant])
case class Company(branches: List[Branch])
def getCompanyValue(company: Company): Int = {
val valuesList = for {
branch <- company.branches
consultant <- branch.consultants
customer <- consultant.portfolio
} yield (customer.value)
valuesList reduce (_ + _)
}
Türünü tahmin edebilir misin valuesList
?
Daha önce de belirtildiği gibi, monad
kavrama yoluyla formun şekli korunur, bu yüzden bir List
in ile başlayıp a company.branches
ile bitmeliyiz List
.
Bunun yerine iç tip değişir ve yield
ifade tarafından belirlenir :customer.value: Int
valueList
olmalı List[Int]