2015-11-28 4 views
7

में बेकार का उपयोग करके विभिन्न प्रकार की एक सूची को फोल्ड करना, जैसा कि मुझे पता है, आकारहीन HList (हैटरोजेनस सूची) प्रकार जिसमें कई प्रकार शामिल हो सकते हैं।स्कैला

क्या HList को फोल्ड करना संभव है? उदाहरण के लिए,

// ref - Composable application architecture with reasonably priced monad 
// code - https://github.com/stew/reasonably-priced/blob/master/src/main/scala/reasonable/App.scala 

import scalaz.{Coproduct, Free, Id, NaturalTransformation} 

def or[F[_], G[_], H[_]](f: F ~> H, g: G ~> H): ({type cp[α] = Coproduct[F,G,α]})#cp ~> H = 
    new NaturalTransformation[({type cp[α] = Coproduct[F,G,α]})#cp,H] { 
    def apply[A](fa: Coproduct[F,G,A]): H[A] = fa.run match { 
     case -\/(ff) ⇒ f(ff) 
     case \/-(gg) ⇒ g(gg) 
    } 
    } 

type Language0[A] = Coproduct[InteractOp, AuthOp, A] 
type Language[A] = Coproduct[LogOp, Language0, A] 

val interpreter0: Language0 ~> Id = or(InteractInterpreter, AuthInterpreter) 
val interpreter: Language ~> Id = or(LogInterpreter, interpreter0) 


// What if we have `combine` function which folds HList 
val interpreters: Language ~> Id = combine(InteractInterpreter :: AuthInterpreter :: LoginInterpreter :: HNil) 

भी, मैं पीढ़ी Langauge की आसान बनाने में कर सकते हैं?

type Language0[A] = Coproduct[InteractOp, AuthOp, A] 
type Language[A] = Coproduct[LogOp, Language0, A] 

// What if we can create `Language` in one line 
type Language[A] = GenCoproduct[InteractOp, AuthOp, LogOp, A] 
+2

आप पॉलिमॉर्फिक फ़ंक्शन का उपयोग करके 'एचएलआईस्ट' को फोल्ड कर सकते हैं। कृपया, [आकारहीन गाइड] (https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#heterogenous-lists) देखें। –

उत्तर

7

एक पूरा काम कर उदाहरण के लिए, मान लीजिए हम कुछ सरल अल्जेब्रास मिल गया है:

sealed trait AuthOp[A] 
case class Login(user: String, pass: String) extends AuthOp[Option[String]] 
case class HasPermission(user: String, access: String) extends AuthOp[Boolean] 

sealed trait InteractOp[A] 
case class Ask(prompt: String) extends InteractOp[String] 
case class Tell(msg: String) extends InteractOp[Unit] 

sealed trait LogOp[A] 
case class Record(msg: String) extends LogOp[Unit] 

और कुछ (व्यर्थ लेकिन संकलन करने योग्य) दुभाषिए:

import scalaz.~>, scalaz.Id.Id 

val AuthInterpreter: AuthOp ~> Id = new (AuthOp ~> Id) { 
    def apply[A](op: AuthOp[A]): A = op match { 
    case Login("foo", "bar") => Some("foo") 
    case Login(_, _) => None 
    case HasPermission("foo", "any") => true 
    case HasPermission(_, _) => false 
    } 
} 

val InteractInterpreter: InteractOp ~> Id = new (InteractOp ~> Id) { 
    def apply[A](op: InteractOp[A]): A = op match { 
    case Ask(p) => p 
    case Tell(_) =>() 
    } 
} 

val LogInterpreter: LogOp ~> Id = new (LogOp ~> Id) { 
    def apply[A](op: LogOp[A]): A = op match { 
    case Record(_) =>() 
    } 
} 

इस बिंदु पर आप इस तरह के दुभाषियों के HList पर गुना करने में सक्षम होना चाहिए:

import scalaz.Coproduct 
import shapeless.Poly2 

object combine extends Poly2 { 
    implicit def or[F[_], G[_], H[_]]: Case.Aux[ 
    F ~> H, 
    G ~> H, 
    ({ type L[x] = Coproduct[F, G, x] })#L ~> H 
    ] = at((f, g) => 
    new (({ type L[x] = Coproduct[F, G, x] })#L ~> H) { 
     def apply[A](fa: Coproduct[F, G, A]): H[A] = fa.run.fold(f, g) 
    } 
) 
} 

लेकिन यह उन कारणों से काम नहीं करता है जो टाइप अनुमान के साथ कुछ करने के लिए प्रतीत होते हैं। यह एक कस्टम प्रकार वर्ग लिखने के लिए भी मुश्किल नहीं है, हालांकि:

import scalaz.Coproduct 
import shapeless.{ DepFn1, HList, HNil, :: } 

trait Interpreters[L <: HList] extends DepFn1[L] 

object Interpreters { 
    type Aux[L <: HList, Out0] = Interpreters[L] { type Out = Out0 } 

    implicit def interpreters0[F[_], H[_]]: Aux[(F ~> H) :: HNil, F ~> H] = 
    new Interpreters[(F ~> H) :: HNil] { 
     type Out = F ~> H 
     def apply(in: (F ~> H) :: HNil): F ~> H = in.head 
    } 

    implicit def interpreters1[F[_], G[_], H[_], T <: HList](implicit 
    ti: Aux[T, G ~> H] 
): Aux[(F ~> H) :: T, ({ type L[x] = Coproduct[F, G, x] })#L ~> H] = 
    new Interpreters[(F ~> H) :: T] { 
     type Out = ({ type L[x] = Coproduct[F, G, x] })#L ~> H 
     def apply(
     in: (F ~> H) :: T 
    ): ({ type L[x] = Coproduct[F, G, x] })#L ~> H = 
     new (({ type L[x] = Coproduct[F, G, x] })#L ~> H) { 
      def apply[A](fa: Coproduct[F, G, A]): H[A] = 
      fa.run.fold(in.head, ti(in.tail)) 
     } 
    } 
} 

और फिर आप अपने combine लिख सकते हैं:

def combine[L <: HList](l: L)(implicit is: Interpreters[L]): is.Out = is(l) 

और इसका इस्तेमाल करते हैं:

type Language0[A] = Coproduct[InteractOp, AuthOp, A] 
type Language[A] = Coproduct[LogOp, Language0, A] 

val interpreter: Language ~> Id = 
    combine(LogInterpreter :: InteractInterpreter :: AuthInterpreter :: HNil) 

आप सक्षम हो सकता है Poly2 संस्करण काम करने के लिए, लेकिन इस प्रकार की कक्षा शायद मेरे लिए पर्याप्त सरल होगी। दुर्भाग्य से आप जिस तरह से चाहते हैं, Language टाइप उपनाम की परिभाषा को सरल बनाने में सक्षम नहीं होंगे।

+0

अच्छा काम करने के उदाहरण के लिए धन्यवाद। – 1ambda