2011-12-30 21 views
9

के लिए Idiomatic Scala समाधान 'idiomatic' स्कैला में इस फ़ंक्शन को व्यक्त करने के लिए कुछ विचार क्या हैं। या अधिक सटीक, क्या पठनीयता को बलि किए बिना स्थानीय युद्धों को हटाने का कोई तरीका है?अनिवार्य कोड

def solve(threshold: Int)(f: Int => Int): Int = { 
    var sum = 0 
    var curr = 0 
    while(sum < threshold) { 
    sum += f(curr) 
    curr += 1 
    } 
    curr 
} 

एकमात्र चीज जिसके साथ मैं आ सकता था, लेकिन यह मेरी राय में लंबा और कम पठनीय था।

def solve2(threshold: Int)(f: Int => Int): Int = { 
    val resultIterator = Iterator.iterate (0, 0) { case (curr, sum) => 
    (curr + 1, sum + f(curr)) 
    } 
    (resultIterator find (_._2 >= threshold)).get._1 
} 
+0

यह जो एक _correct_ बनाने के लिए के बाद से सभी इतना अच्छा मैं एक है कि करने के लिए सबसे सहज लग रहा था उठाया थे तय करने के लिए मुश्किल था मुझे –

+0

@ डैन बर्टन के समाधान ने मुझे टूलबॉक्स के लिए सबसे नई युक्तियां दीं। –

उत्तर

10

सबसे प्रत्यक्ष दृष्टिकोण है जबकि लूप को नेस्टेड पूंछ-पुनरावर्ती समारोह में बदलना है।

def solve(threshold: Int)(f: Int => Int): Int = { 
    def solveLoop(sum: Int, curr: Int): Int = if (sum < threshold) { 
     solveLoop(sum + f(curr), curr + 1) 
    } else { 
     curr 
    } 
    solveLoop(0,0) 
} 

यह पाशन के मानक "कार्यात्मक" तरीका है।

+0

प्रतिबिंब पर, यह केवल मेरे "जब तक" समाधान का अनौपचारिक संस्करण है। :) –

13
def solve(threshold: Int)(f: Int => Int): Int = { 
    Iterator.from(0).map(f).scanLeft(0)(_ + _).indexWhere(threshold <=) 
} 

मेरी राय में, लूप संस्करण बहुत स्पष्ट है।

7

आप कर सकते थे

def solve(threshold: Int, i: Int = 0)(f: Int => Int) = { 
    if (threshold <= 0) i else solve(threshold - f(i), i+1)(f) 
} 

लेकिन मुझे यकीन है कि वास्तव में स्पष्ट है नहीं कर रहा हूँ। ध्यान दें कि यह वास्तव में, जबकि पाश की एक कॉम्पैक्ट संस्करण की तुलना में अधिक वर्ण है:

परिवर्तनशील चर के साथ
def solve(threshold: Int)(f: Int => Int) = { 
    var s,i = 0; while (s < threshold) { s += f(i); i += 1 }; i 
} 

लूप्स हमेशा बुरा, "मुहावरेदार" या नहीं कर रहे हैं। केवल म्यूटेबल स्टेटस को फ़ंक्शन के भीतर सुरक्षित रूप से निहित रखें, और किसी और को देखकर कॉल करने के लिए एक स्टेटलेस फ़ंक्शन है।

संयोग से, हालांकि sum एक समझदार चर नाम है, curr संदिग्ध है। i के साथ क्या गलत है? यह व्यापक रूप से एक इंडेक्स वैरिएबल के रूप में उपयोग किया जाता है, और वैसे भी, एक चर होने पर एक उपद्रव है; मुद्दा यह है कि आप कुछ लेते हैं और इसे बढ़ाते हैं, जो भी हो, हर बार एक कदम से, और फिर इसे वापस कर दें। यह तर्क का यह प्रवाह है, नाम नहीं, जो आपको बताता है (और अन्य) इसके लिए क्या है।

+0

मुझे 'curr' विचलन भी मिला। – huynhjl

+0

आप परिवर्तनीय नामकरण के बारे में सही हैं। मैं केवल मूल संदर्भ में कह सकता हूं कि नाम थोड़ा और अधिक समझ में आया है। –

1

मुझे हमेशा आश्चर्य होता है जब लोग 'idiomatic' scala के बारे में बात करते हैं। क्योंकि मेरी राय में हर किसी के पास मूर्खता की अपनी धारणा है। यदि आप एक कार्यात्मक समाधान की तलाश में हैं, तो मैं आपको 'इटरेटर पैटर्न का सार' देखने के लिए सुझाव देना चाहता हूं। ,

solve threshold f = snd $ until test step (0, 0) 
    where test (sum, i) = sum >= threshold 
     step (sum, i) = (sum + f i, succ i) 

यह स्पष्ट रूप से test निशान step, और प्रारंभिक: http://etorreborre.blogspot.com/2011/06/essence-of-iterator-pattern.html

+0

क्या आप कृपया कुछ कोड के साथ दिखा सकते हैं कि यहां 'ट्रैवर्स' प्रासंगिक कैसे है? – missingfaktor

+0

ठीक है अगर आप देखें: थ्रेसहोल्ड, योग और cur। वह उन मूल्यों के साथ क्या करता है? वह उन मूल्यों का एक सीमित 'धारा' उत्पन्न करने के लिए उपयोग करता है, जो वह अपने कार्य को लागू करने के बजाय करता है। आश्वस्त?:) – AndreasScheinert

+0

ठीक है अगर आप देखें: थ्रेसहोल्ड, योग और cur। वह उन मूल्यों के साथ क्या करता है? वह उन मूल्यों का एक सीमित 'धारा' उत्पन्न करने के लिए उपयोग करता है, जो वह अपने कार्य को लागू करने के बजाय करता है। आश्वस्त? असल में, मुझे स्कैनलेफ्ट कार्यान्वयन बेहतर पसंद है। Idiomatic बहुत ही व्यक्तिपरक है, कुछ लोगों का मतलब terse या क्या कभी है। राज्य को थ्रेड करते समय एक अनुक्रम उत्पन्न करना और फ़ंक्शन को लागू करना। यह निर्भर करता है कि आप इसे कैसे व्यक्त करना चाहते हैं। – AndreasScheinert

4

यहाँ कैसे मैं हास्केल में यह करना होगा है: वहाँ वास्तव में इस बारे में स्केला में एक बहुत अच्छा ब्लॉग पोस्ट यहाँ यह बाहर की जाँच है मूल्य, केवल अनिवार्य संस्करण की तरह। मुझे यकीन है कि अगर स्केला कहीं libs में until है नहीं कर रहा हूँ, लेकिन यह परिभाषित करने के लिए मामूली बात है:

def until[A](test: A => Boolean)(f: A => A)(v: A): A = { 
    if (test(v)) { 
    v 
    } else { 
    until(test)(f)(f(v)) 
    } 
} 

def solve(threshold: Int)(f: Int => Int): Int = { 
    def test = (sum: Int, i: Int) => sum >= threshold 
    def step = (sum: Int, i: Int) => (sum + f(i), i + 1) 
    until(test.tupled)(step.tupled)((0, 0))._2 
} 
+2

+1, यह एक बहुत आसान समारोह की तरह दिखता है। आपको अपने उत्तर आईएमओ में समकक्ष स्कैला जोड़ना चाहिए। – missingfaktor

+0

@missingfaktor किया :) मैंने कल रात अपने मूल फोन को लिखा था और स्कैला में इसका परीक्षण करने के लिए बहुत आलसी था। सुनिश्चित नहीं हैं कि यहां currying की मेरी ज़्यादा इस्तेमाल स्काला की पूंछ कॉल अनुकूलन के साथ संगत है, लेकिन मैं क्या मैं हास्केल के currying तरह कह सकते हैं, यदि। –

संबंधित मुद्दे