Kleisli arrow

Představte si, že mám dvě funkce:
val f: String => List[File] val g: File => List[Tweet]
A potřeboval bych je spojit do následující funkce:
val r: String => List[Tweet]
Tedy něco ve stylu monadického flatMap: f flatMap g
. Takhle přímo by to fungovalo, kdyby f
nebyla funkce String => List[File]
, ale rovnou List[File]
.
Implementace bez použití knihovny ScalaZ by mohla vypdat následovně:
val r = (arg: String) => for { ff <- f(arg); gg <- g(ff) } yield gg val r = (arg: String) => f(arg) flatMap { g(_) }
ScalaZ nabízí Kleisli Arrow, který tento problém krásně vyřeší point-free stylem:
val r = kleisli(f) >=> g
Takto se dá řetězit i víc funkcí: kleisli(a) >=> b >=> c
a výsledek je pořád „plochá“ funkce typu A => M[D]
(nikoli A => M[M[M[D]]]
).
<=<
funguje stejně ale v opačném směru, takže a >=> b <=< x
je stejné jako (a >=> b) <=< x
nebo x >=> a >=> b
.
Pak je k dispozici ještě operátor =<<
, pro který platí, že f =<< list
je obdoba list.flatMap(f)
.
Následující dva řádky kódu se chovají stejně, ale přistupují k věci jinak.
Kleisli Arrow nejdřív pomocí kombinátorů spojí několik jednoduchých funkcí a pak na ně operátorem =<<
aplikuje kolekci; druhý řádek začíná s kolekcí a pak
na ni popořadě aplikuje jednotlivé funkce.
f >=> g =<< List("/home/adam-k/data/dir1", "/home/adam-k/data/dir2") List("/home/adam-k/data/dir1", "/home/adam-k/data/dir2") flatMap f flatMap g
Více k tématu zde:
* https://wiki.scala-lang.org/display/SW/Kleisli+Monad * http://www.cakesolutions.net/teamblogs/2011/09/16/kleisli-arrows/ * http://www.cakesolutions.net/teamblogs/2011/09/18/kleisli-arrows-ii/
PS: A pokud máte rádi unicode, tak ☆
je synonymem funkce kleisli
.