5

F, [G [A]] nesneye fonksiyonu:Scalaz monad transformatörleri. Başvuru f1: A => G, [B], f2: B => G, [C] 'iki (veya daha fazla) işlevleri olarak tanımladığımız

val functionM: String => Option[Int] = s => Some(s.length) 
val functionM2: Int => Option[String] = i => Some(i.toString) 

Ayrıca bazı veriler tanımlamıştır:

val data: List[Option[String]] = List(Option("abc")) 

sorum gibi bir sonuç elde etmek için (güzel bir şekilde) fonksiyonlarını oluşturmak için yapılması gerekenler:

data.map(_.flatMap(functionM).flatMap(functionM2)) 
res0: List[Option[String]] = List(Some(3)) 

ben li yok Yukarıdaki işlev çağrılarının sözdizimi. Böyle birçok yer varsa, kod çok okunamaz.

Ben OptionT scalaz monad trafosu ile oynamak çalıştı, ama yine de haritalar yuvalanmış ve ayrıca gibi iç içe geçmiş Seçenek oluşturur:

:

OptionT(data).map(a => functionM(a).map(functionM2)).run 
res2: List[Option[Option[Option[String]]]] = List(Some(Some(Some(3)))) 

Ne elde etmek istiyorum az çok böyle bir şeydir

Something(data).map(functionM).map(functionM2) 

veya daha iyi:

val functions = functionM andThenSomething functionM2 
Something(data).map(functions) 

Try ile çalışabilirse iyi olur. Scalaz'ın TryT monad transformatörüne sahip olmadığını biliyorum, bu yüzden Try üzerinde çalışan fonksiyonları güzel bir şekilde oluşturmak için herhangi bir yol var mı?

+0

'val işlevleri = functionM ve AfterSomething functionM2' işlevlerini' 'Kleisli (functionM)> => Kleisli (functionM2)' ile yapabilirsiniz, ancak bununla ne yapacağına emin değilim ... –

cevap

7

Łukasz'dan da anlaşılacağı gibi, Kleisli burada en alakalı gibi görünüyor. Her zaman şeklin A => F[B] bazı işlevlere sahiptir ve onlar sıradan fonksiyonlar A => B sanki onları oluşturmak istiyorum (ve F için flatMap sahipse), Kleisli oklar gibi işlevleri temsil edebilir:

import scalaz._, Scalaz._ 

val f1: Kleisli[Option, String, Int] = Kleisli(s => Some(s.length)) 
val f2: Kleisli[Option, Int, String] = Kleisli(i => Some(i.toString)) 

Ve sonra: Eğer okuyucu monadın fikrine aşina iseniz, Kleisli sadece fikri çerçeveleme bir biraz daha genel bir yoldur -çok ReaderT tam olarak aynı şeydir

scala> f1.andThen(f2).run("test") 
res0: Option[String] = Some(4) 

(daha fazla ayrıntı için benim cevap here bkz).

Bu durumda, monofon transformatörlerinin aradığınız şey olması pek olası görünmüyor, çünkü'un içinde doğrudan doğruya A10 s ile çalışmaya devam etmiyorsunuz - iki seviyeyi ayrı tutuyorsunuz.

scala> val data: List[Option[String]] = List(Option("abc")) 
data: List[Option[String]] = List(Some(abc)) 

scala> data.map(_.flatMap(f1.andThen(f2))) 
res1: List[Option[String]] = List(Some(3)) 

Son olarak, Scalaz bir Monad (burada ihtiyacım olacağını nedir ya Bind) sağlamaz sırf örneği: f1 ve üzeri f2 tanımları göz önüne alındığında, muhtemelen sadece aşağıdaki yazardım Try için, bu kendi yazamadığınız anlamına gelmez.Sonra

import scala.util.{ Success, Try } 

implicit val bindTry: Bind[Try] = new Bind[Try] { 
    def map[A, B](fa: Try[A])(f: A => B): Try[B] = fa.map(f) 
    def bind[A, B](fa: Try[A])(f: A => Try[B]): Try[B] = fa.flatMap(f) 
} 

val f1: Kleisli[Try, String, Int] = Kleisli(s => Success(s.length)) 
val f2: Kleisli[Try, Int, String] = Kleisli(i => Success(i.toString)) 

Ve: Örneğin:

scala> val data: List[Try[String]] = List(Try("abc")) 
data: List[scala.util.Try[String]] = List(Success(abc)) 

scala> data.map(_.flatMap(f1.andThen(f2))) 
res5: List[scala.util.Try[String]] = List(Success(3)) 

Bazı insanlar istisnalar varlığında Try için böyle bir Functor veya Monad veya Bind örneğinin hukukiliği hakkında bazı endişeler var ve bu insanlar eğilimindedir yüksek sesle insanlar olmak için, ama ben bunu zor buluyorum (benim görüşüme göre Try'u tamamen önlemek için vardır).

+0

Kleisli kullanımı için bir gelişme var. . Eğer yuvalanmış haritayı kullanmaktan kaçınmak istiyorsak OptionT trafosunu kullanabiliriz. içe scalaz._, Scalaz._ val f1: Kleisli [Seçenek, String, Uluslararası] = Kleisli (s => Bazı (s.length)) val f2: Kleisli [Seçenek, Int String] = Kleisli (i => Bazı (i.toString)) val f3: Kleisli [Option, String, String] = Kleisli (s => Bazı (s + "merhaba")) val işlevleri: Kleisli [Seçenek, Dize, Dize ] = f1 ve Sonrasında f2 ve Sonrasında f3 val verileri: Liste [Seçenek [Dize]] = Liste (Seçenek ("abc")) OptionT.optionT (data) .map (functions) .run.flatten – NieMaszNic

İlgili konular