आप एक for
-comprehension या map
का एक संयोजन और समारोह शाब्दिक यहाँ के साथ flatMap
उपयोग कर सकते हैं नहीं है (जैसा कि अन्य उत्तर सुझाव है), के बाद से HList
पर इन तरीकों higher rank functions आवश्यकता होती है। तुम सिर्फ दो स्थिर टाइप किया सूचियों है, तो यह आसान है:
import shapeless._
val xs = 1 :: 'b :: 'c' :: HNil
val ys = 4.0 :: "e" :: HNil
object eachFirst extends Poly1 {
implicit def default[A] = at[A] { a =>
object second extends Poly1 { implicit def default[B] = at[B](a -> _) }
ys map second
}
}
val cartesianProductXsYs = xs flatMap eachFirst
निम्नलिखित (उचित रूप से टाइप किया) हमें देता है कौन सा:
(1,4.0) :: (1,e) :: ('b,4.0) :: ('b,e) :: (c,4.0) :: (c,e) :: HNil
एक विधि है कि जटिल काम है HList
तर्क के साथ यह कर देगा लेखन। यहां एक त्वरित उदाहरण दिया गया है कि यह कैसे किया जा सकता है (कुछ और अधिक सामान्य मशीनरी के साथ)।
मैं यह ध्यान में रखकर शुरू करूंगा कि हम दो सामान्य सूचियों के कार्टेशियन उत्पाद को "उठाने" के रूप में सोचने के बारे में सोच सकते हैं जो दो तर्क लेता है और उन्हें सूचियों के लिए आवेदक मज़ेदार में टुपल के रूप में लौटाता है। उदाहरण के लिए, आप the following in Haskell लिख सकते हैं:
import Control.Applicative (liftA2)
cartesianProd :: [a] -> [b] -> [(a, b)]
cartesianProd = liftA2 (,)
हम बहुरूपी द्विआधारी समारोह है कि (,)
यहाँ से मेल खाती है लिख सकते हैं:
val xs = 1 :: 'b :: 'c' :: HNil
val ys = 4.0 :: "e" :: HNil
:
import shapeless._
object tuple extends Poly2 {
implicit def whatever[A, B] = at[A, B] { case (a, b) => (a, b) }
}
और हमारे उदाहरण परिभाषित संपूर्णता के लिए फिर से सूचीबद्ध करता है
अब हम liftA2
नामक एक विधि की ओर काम करेंगे जो हमें निम्नलिखित लिखने की अनुमति देगा:
liftA2(tuple)(xs, ys)
और सही परिणाम प्राप्त करें। नाम liftA2
थोड़ा भ्रामक है, क्योंकि हमारे पास वास्तव में कोई आवेदक फ़ैक्टर उदाहरण नहीं है, और चूंकि यह सामान्य नहीं है- मैं flatMap
और map
नामक विधियों के मॉडल पर काम कर रहा हूं HList
पर, और कुछ के लिए सुझावों के लिए खुला हूं बेहतर।
trait ApplyMapper[HF, A, X <: HList, Out <: HList] {
def apply(a: A, x: X): Out
}
object ApplyMapper {
implicit def hnil[HF, A] = new ApplyMapper[HF, A, HNil, HNil] {
def apply(a: A, x: HNil) = HNil
}
implicit def hlist[HF, A, XH, XT <: HList, OutH, OutT <: HList](implicit
pb: Poly.Pullback2Aux[HF, A, XH, OutH],
am: ApplyMapper[HF, A, XT, OutT]
) = new ApplyMapper[HF, A, XH :: XT, OutH :: OutT] {
def apply(a: A, x: XH :: XT) = pb(a, x.head) :: am(a, x.tail)
}
}
और अब के साथ मदद करने के लिए एक प्रकार वर्ग:
अब हम एक प्रकार वर्ग है कि हम एक HList
पर एक Poly2
लेने के लिए, आंशिक रूप से कुछ करने के लिए इसे लागू होते हैं, और नक्शा जिसके परिणामस्वरूप एकल समारोह की अनुमति देगा की जरूरत है उठाने:
trait LiftA2[HF, X <: HList, Y <: HList, Out <: HList] {
def apply(x: X, y: Y): Out
}
object LiftA2 {
implicit def hnil[HF, Y <: HList] = new LiftA2[HF, HNil, Y, HNil] {
def apply(x: HNil, y: Y) = HNil
}
implicit def hlist[
HF, XH, XT <: HList, Y <: HList,
Out1 <: HList, Out2 <: HList, Out <: HList
](implicit
am: ApplyMapper[HF, XH, Y, Out1],
lift: LiftA2[HF, XT, Y, Out2],
prepend : PrependAux[Out1, Out2, Out]
) = new LiftA2[HF, XH :: XT, Y, Out] {
def apply(x: XH :: XT, y: Y) = prepend(am(x.head, y), lift(x.tail, y))
}
}
और अंत में हमारे विधि में ही:
def liftA2[HF, X <: HList, Y <: HList, Out <: HList](hf: HF)(x: X, y: Y)(implicit
lift: LiftA2[HF, X, Y, Out]
) = lift(x, y)
और यह सब अब liftA2(tuple)(xs, ys)
काम करता है।
scala> type Result =
| (Int, Double) :: (Int, String) ::
| (Symbol, Double) :: (Symbol, String) ::
| (Char, Double) :: (Char, String) :: HNil
defined type alias Result
scala> val res: Result = liftA2(tuple)(xs, ys)
res: Result = (1,4.0) :: (1,e) :: ('b,4.0) :: ('b,e) :: (c,4.0) :: (c,e) :: HNil
जैसे हम चाहते थे।
सटीक रूप से आप "_function_" और "कोड के एक रेखांकित ब्लॉक" के बीच क्या अंतर आकर्षित करते हैं? –
@RandallSchulz: नीचे ट्रैविस के पहले उत्तर और लिफ्टए 2 का उपयोग करके उनके अंतिम उत्तर के बीच अंतर देखें। – emchristiansen