2015-07-24 8 views
5

मैं Project Euler Problem #2 करने के लिए मेरे निराकार समाधान पर शुरू कर दिया है।स्काला निराकार कोड 2

मैं इस कोड के साथ Nth भी एक अप करने के लिए एक साथ सभी भी fibs जोड़ सकते हैं:

import shapeless._, nat._, ops.nat.Sum 

trait Fibonacci[N <: Nat] { type Out <: Nat } 

object Fibonacci { 
    type Aux[N <: Nat, Out0 <: Nat] = Fibonacci[N] { type Out = Out0 } 

    def apply[N <: Nat](i: Nat)(implicit fib: Aux[i.N, N], n: Witness.Aux[N]):N = n.value 

    implicit val fib0 = new Fibonacci[_0] { type Out = _2 } 
    implicit val fib1 = new Fibonacci[_1] { type Out = _3 } 

    implicit def fibN[I <: Nat, L <: Nat, M <: Nat](implicit l: Aux[I, L], 
                m: Aux[Succ[I], M], 
                sum: Sum[L, M]) = 
    new Fibonacci[Succ[Succ[I]]] { type Out = sum.Out } 
} 

trait Fibs[N <: Nat] { type Out <: Nat } 

object Fibs { 
    type Aux[N <: Nat, Out0 <: Nat] = Fibs[N] { type Out = Out0 } 

    def apply[N <: Nat](i: Nat)(implicit fibs: Aux[i.N, N], n: Witness.Aux[N]):N = n.value 

    implicit def fibs0(implicit f: Fibonacci[_0]) = new Fibs[_0] { type Out = f.Out } 

    implicit def fibsN[N <: Nat, R <: Nat, Z <: Nat](implicit fib: Fibonacci.Aux[Succ[Succ[Succ[N]]], R], 
                fibs: Aux[N, Z], 
                sum: Sum[R, Z]) = 
    new Fibs[Succ[N]] { 
     type Out = sum.Out 
    } 
} 

अब मैं कर सकते हैं:

val (evenFibs0, evenFibs1) = (Fibs(0), Fibs(1)) 
typed[_2](evenFibs0) 
typed[_10](evenFibs1) 

यह कैसे मैं सभी भी fibs मिलता है: मैं अनुक्रम 2, 3, ... के साथ शुरू करता हूं, और मैं हर तीसरे फिबोनाची संख्या को जोड़ता हूं।

अब, मैं अटक कर रहा हूँ। मैं takeWhile के समान कार्यक्षमता करना चाहते हैं, तो मैं एक समारोह है कि एक limit स्वीकार करता है और मेरी भी fibs जिसका शर्तों कि सीमा से अधिक नहीं है का योग देता है लिख सकते हैं। कोई विचार?

यहाँ मैं अब तक क्या कोशिश की है के लिए मेरे प्रयास है:

trait EvenFibsWithLimit[N <: Nat, M <: Nat] { type Out <: Nat } 

trait LowPriorityFibs3 { 
    type Aux[N <: Nat, M <: Nat, Out0 <: Nat] = EvenFibsWithLimit[N, M] { type Out = Out0 } 

    implicit def fibs0[M <: Nat] = new EvenFibsWithLimit[_0, M] { type Out = _0 } 

    implicit def fibsGT[N <: Nat, M <: Nat, O <: Nat](implicit f: EvenFibsWithLimit[N, M], 
                fib: Fibs.Aux[N, O], 
                l: ops.nat.LT[M, O]) = f 
} 

object EvenFibsWithLimit extends LowPriorityFibs3 { 
    def apply[N <: Nat, O <: Nat](limit: Nat)(implicit fibs: Aux[N, limit.N, O], 
              o: Witness.Aux[O]): O = o.value 

    implicit def fibsN[N <: Nat, M <: Nat, O <: Nat](implicit f: EvenFibsWithLimit[N, M], 
                f2: Fibs.Aux[Succ[N], O], 
                d: ops.nat.Diff[M, O]) = 
    new EvenFibsWithLimit[Succ[N], d.Out] { 
     type Out = O 
    } 
} 

विचार रिकर्सिवली उत्पादन द्वारा सीमा घटाने के लिए जब तक उत्पादन सीमा से कम है था। मैं निश्चित रूप से कुछ गंध कर सकता हूँ। मुझे नहीं लगता कि मुझे Diff बिल्कुल चाहिए .. मैंने कुछ अन्य बदलावों की भी कोशिश की है, लेकिन मैं अटक गया हूं।

मैं शायद सोच रहा था मैं अपने Fibs के HList निर्माण कर सकते हैं, और एक विधेय typeclass साथ Selector का प्रयोग कर एक takeWhile अनुकरण करने के लिए: जब मैं संकलन, मैं त्रुटि diverging implicit expansion for fibsN.

संपादित मिलता है। विचार?

उत्तर

5

मुझे लगता है इस तरह की समस्या के दृष्टिकोण का सबसे अच्छा तरीका प्राकृतिक संख्या से निकलने के लिए, जबकि जानकारी मैं का ट्रैक रखने की जरूरत के बारे में सोच रहा है।

कागज पर मैं कुछ इस तरह का उपयोग करेंगे:

N 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
C 1 2 3 3 5 5 5 8 8 8 8 8 13 13 13 
P 1 1 2 2 3 3 3 5 5 5 5 5 8 8 8 
L 0 2 2 2 2 2 2 10 10 10 10 10 10 10 10 

यहाँ C फाइबोनैचि अनुक्रम-यानी में वर्तमान संख्या ट्रैक करता है। सबसे बड़ा जो N से कम या उसके बराबर है। P इससे पहले फिबोनाची संख्या है, और L उन लोगों की वर्तमान योग है जिन्हें हमने अभी तक देखा है।

हम एक प्रकार वर्ग में इस अनुवाद कर सकते हैं:

import shapeless._, ops.nat.{ Mod, Sum }, nat.{ _0, _1, _2 } 

trait EvenFibs[N <: Nat] { 
    type L <: Nat 
    type C <: Nat 
    type P <: Nat 
} 

अब चार मामलों में हम संभाल करने की जरूरत है।

trait LowPriorityEvenFibs { 
    type Aux[N <: Nat, L0 <: Nat, C0 <: Nat, P0 <: Nat] = EvenFibs[N] { 
    type L = L0 
    type C = C0 
    type P = P0 
    } 

    implicit def ef3[N <: Nat](implicit 
    ef: EvenFibs[N] 
): Aux[Succ[N], ef.L, ef.C, ef.P] = new EvenFibs[Succ[N]] { 
    type L = ef.L 
    type C = ef.C 
    type P = ef.P 
    } 
} 

इस मामले में जहां Succ[N] एक फाइबोनैचि संख्या नहीं है: सबसे पहले मैं एक आदेश निहित संकल्प सही पाने के लिए सबसे कम प्राथमिकता की जरूरत है कि दे देंगे। हमें उन मूल्यों को अपडेट करने की आवश्यकता नहीं है जिन्हें हम ट्रैक रखते हैं।

trait MidPriorityEvenFibs extends LowPriorityEvenFibs { 
    implicit def ef2[N <: Nat, L0 <: Nat, PP <: Nat, P0 <: Nat](implicit 
    ef: Aux[N, L0, P0, PP], 
    sum: Sum.Aux[PP, P0, Succ[N]] 
): Aux[Succ[N], L0, Succ[N], P0] = new EvenFibs[Succ[N]] { 
    type L = L0 
    type C = Succ[N] 
    type P = P0 
    } 
} 

इस मामले में जहां Succ[N] एक अजीब फाइबोनैचि संख्या है है: अगले मामले में एक छोटे से अधिक जटिल है। इस मामले में हम C और P, लेकिन नहीं L अपडेट करना होगा।

हमारा अंतिम Succ[N] केस वह है जहां Succ[N] एक फाइबोनैकी संख्या भी है।

object EvenFibs extends MidPriorityEvenFibs { 
    implicit def ef0: Aux[_0, _0, _1, _1] = new EvenFibs[_0] { 
    type L = _0 
    type C = _1 
    type P = _1 
    } 

    implicit def ef1[N <: Nat, L <: Nat, PP <: Nat, P0 <: Nat](implicit 
    ef: Aux[N, L, P0, PP], 
    sum: Sum.Aux[PP, P0, Succ[N]], 
    mod: Mod.Aux[Succ[N], _2, _0], 
    current: Sum[Succ[N], L] 
): Aux[Succ[N], current.Out, Succ[N], P0] = new EvenFibs[Succ[N]] { 
    type L = current.Out 
    type C = Succ[N] 
    type P = P0 
    } 

    def apply[N <: Nat](implicit ef: EvenFibs[N]): Aux[N, ef.L, ef.C, ef.P] = ef 
} 

अन्त में हम एक सहायक वर्ग को परिभाषित कर सकते हैं यह आसान हमारे काम की जांच करने के कर देगा कि:

class ComputeHelper[N <: Nat] { 
    def value[L <: Nat, C <: Nat, P <: Nat](implicit 
    ef: EvenFibs.Aux[N, L, C, P], 
    wit: Witness.Aux[L] 
): L = wit.value 
} 

def compute[N <: Nat]: ComputeHelper[N] = new ComputeHelper[N] 

और फिर:

test.typed[_0](compute[_0].value) 
test.typed[_0](compute[_1].value) 
test.typed[_2](compute[_2].value) 
test.typed[_2](compute[nat._3].value) 
test.typed[_2](compute[nat._4].value) 
test.typed[_2](compute[nat._5].value) 
test.typed[_2](compute[nat._6].value) 
test.typed[_2](compute[nat._7].value) 
test.typed[nat._10](compute[nat._8].value) 
test.typed[nat._10](compute[nat._9].value) 
मैं इसे यहाँ आधार मामले से दे देंगे

अंतिम पंक्ति में मेरी मशीन पर संकलन करने के लिए लगभग बीस सेकंड लगते हैं, लेकिन यह काम करता है।

+0

अच्छी तकनीक। मैं अब चीजों की लटकना शुरू कर रहा हूं, धन्यवाद। – beefyhalo