TL; DR doğrudan son örneğe gider
Deneyeceğim ve özetleyeceğim.
Tanımlar
forAnlama birleştirmek için bir sözdizimi kısayoldur flatMapve mapokumak ve yaklaşık sebebi kolay bir şekilde.
İşleri biraz basitleştirelim ve classyukarıda bahsedilen her iki yöntemi sağlayan her birinin a olarak adlandırılabileceğini monadve iç tipi ile M[A]a anlamına gelmek için sembolü kullanacağımızı varsayalım .monadA
Ö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, flatMapbir 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 mapifade, 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, mapişlem orijinalin "şeklini" korur monad, bu nedenle yieldifade için de aynı şey olur : a , içindeki işlem tarafından dönüştürülen içerik ile a olarak Listkalır .Listyield
Diğer yandan, içindeki her cilt çizgisi, tek bir "dış şekli" korumak için "düzleştirilmesi" gereken forardışı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 forsö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 mapişlemin eklenmesiyle kolayca "düzleştirmek" tir .
Umarım bu, mekanik bir şekilde uygulanan çeviri seçiminin arkasındaki mantığı açıklar, yani n flatMaptek 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, monadkavrama yoluyla formun şekli korunur, bu yüzden bir Listin ile başlayıp a company.branchesile bitmeliyiz List.
Bunun yerine iç tip değişir ve yieldifade tarafından belirlenir :customer.value: Int
valueList olmalı List[Int]