Scalaz

2012-02-23 17 views
11

ile uygulamalara işlevler nasıl oluşturulur Scalaz 6'u öğrenirken, doğrulamaya geri dönen türlerde güvenli okuyucular yazmaya çalışıyorum.Scalaz

type ValidReader[S,X] = (S) => Validation[NonEmptyList[String],X] 
type MapReader[X] = ValidReader[Map[String,String],X] 

ve iki ints ve dizeleri için harita-okuyucuları oluştururken fonksiyonları (*) var: İşte benim yeni türleridir

def readInt(k: String): MapReader[Int] = ... 
def readString(k: String): MapReader[String] = ... 

aşağıdaki haritası Verilen:

val data = Map("name" -> "Paul", "age" -> "8") 

ben adı ve yaşı almak için iki okuyucu yazabilir:

val name = readString("name") 
val age = readInt("age") 

println(name(data)) //=> Success("Paul") 
println(age(data)) //=> Success(8) 

Her şey çalışıyor, ama şimdi bir Boy örneği oluşturmak için hem okuyucuları oluşturmak istiyorum:

case class Boy(name: String, age: Int) 

En iyi almaktır: Bu beklenen işleri olarak

val boy = (name |@| age) { 
    (n,a) => (n |@| a) { Boy(_,_) } 
    } 
    println(boy(data)) //=> Success(Boy(Paul,8)) 

ama ifadesi ile garip iki seviyeli uygulama kurucuları. Aşağıdaki sözdizimini çalışmak için bir yol var mı?

val boy = (name |@| age) { Boy(_,_) } 

(*) Tam ve katedilebilen uygulanması: https://gist.github.com/1891147


Güncelleme: İşte üstünde veya Daniel öneri hattını çalışırken alıyorum derleyici hata iletisi:

[error] ***/MapReader.scala:114: type mismatch; 
[error] found : scalaz.Validation[scalaz.NonEmptyList[String],String] 
[error] required: String 
[error] val boy = (name |@| age) { Boy(_,_) } 
[error]         ^
+0

ama bir ipucu olarak, unutmayın “Uygulayıcı [G] ve“ Uygulayıcı [F] ”,“ Uygulayıcı [[x] F [G [x]] ”anlamına gelir. Scalaz 7'de, “Uygulayıcı # kompozisyon” bu gerçeğe tanıklık ediyor. '| @ |' Sözdizimini kullanmak yerine, doğrudan başlamak için tip sınıflarıyla çalışın. – retronym

+0

Teşekkürler, ama hala anlamadım, bu yüzden cevabınızı bekleyeceğim. Scalaz 6 kullanıyorum (soru güncellendi). – paradigmatic

+0

@paradigmatic "apply" ı kullanmayı açıkça denediniz mi?(Isim | @ | yaş) gibi {Boy (_, _)} 'gibi? –

cevap

5

Bu nasıl?

val boy = (name |@| age) { 
    (Boy.apply _).lift[({type V[X]=ValidationNEL[String,X]})#V] 
} 

veya bir tür takma adını kullanarak:

type VNELStr[X] = ValidationNEL[String,X] 

val boy = (name |@| age) apply (Boy(_, _)).lift[VNELStr] 

Bu konsolda aşağıdaki hata iletisi dayanmaktadır:

scala> name |@| age apply Boy.apply 
<console>:22: error: type mismatch; 
found : (String, Int) => MapReader.Boy 
required: (scalaz.Validation[scalaz.NonEmptyList[String],String], 
      scalaz.Validation[scalaz.NonEmptyList[String],Int]) => ? 

Yani sadece gerekli tipini almaya Boy.apply kaldırdı.

+0

Teşekkürler. Kaldırma hakkında düşünmedim. Ancak, lambda tipi çorba kaskad içinde iki uygulamalı inşaatçılar kullanarak daha okunabilir olduğundan emin değilim. Yapıcının gizli dönüşümlerden kaldırılmasını sağlamanın bir yolu var mı? – paradigmatic

+0

@paradigmatic, bence bir tür takma adı en okunabilir hale getiriyor. Ayrıca iki nedenden dolayı varsayımsal bir örtük dönüşümü tercih ederim: (1) bana türünü anlatır (Boy (_, _)). [VNELStr] 'lambda - senin türünü bulamadım. sürümü. (2) aynı sebepten dolaylı olarak 'Int' 'seçeneğini değiştirmek istemiyorum. [Int] 'Ben lambanın dönüştürülmesini dolaylı olarak değiştirdiğimi düşünüyorum tip sistemini kullanarak alır. – huynhjl

+0

@huynjl Ben tür takma adı seviyorum ve ben senin noktasını görüyorum. Teşekkürler. – paradigmatic

2

Not: Reader ve Validation (bir E grubuyla) her ikisi de Uygulamalıdır, bunların bileşimi de Uygulamalıdır.

import scalaz.Reader 
import scalaz.Reader.{apply => toReader} 
import scalaz.{Validation, ValidationNEL, Applicative, Kleisli, NonEmptyList} 

//type IntReader[A] = Reader[Int, A] // has some ambigous implicit resolution problem 
type IntReader[A] = Kleisli[scalaz.IdInstances#Id, Int, A] 
type ValNEL[A] = ValidationNEL[Throwable, A] 

val app = Applicative[IntReader].compose[ValNEL] 

Şimdi kompoze uygulamalı tek |@| işlemi kullanabilirsiniz:: scalaz 7 kullanarak bu şekilde ifade edilebilir daha sonra bir cevap göndeririz

val f1 = toReader((x: Int) => Validation.success[NonEmptyList[Throwable], String](x.toString)) 
val f2 = toReader((x: Int) => Validation.success[NonEmptyList[Throwable], String]((x+1).toString)) 

val f3 = app.map2(f1, f2)(_ + ":" + _) 

f3.run(5) should be_==(Validation.success("5:6")) 
+0

Belirsiz örtük karar hakkında, http://stackoverflow.com/questions/11913128/scalaz-7-why-using-type-alias-results-in-ambigous-typeclass-resolution-for-rea – ron

+0

'u açtım Ne yazık ki ihtiyacınız var kapsamdaki kimlik örneğini almak için scalaz.Id._' dosyasını içe aktarmak. Fakat o zaman Reader [Int, A] 'yi kullanabilmelisiniz. – retronym

İlgili konular