एफ # में नेस्टेडनेस के मनमाने स्तर की सूचियों पर सारांश


10

मैं एक एफ # फ़ंक्शन बनाने की कोशिश कर रहा हूं intजो मनमाने ढंग से नेस्टेडनेस की सूची की राशि लौटाएगा । अर्थात। यह a list<int>, a list<list<int>>और a के लिए काम करेगा list<list<list<list<list<list<int>>>>>>

हास्केल में मैं कुछ इस तरह लिखूंगा:

class HasSum a where
    getSum :: a -> Integer

instance HasSum Integer where
    getSum = id

instance HasSum a => HasSum [a] where
    getSum = sum . map getSum

जो मुझे करने देगा:

list :: a -> [a]
list = replicate 6

nestedList :: [[[[[[[[[[Integer]]]]]]]]]]
nestedList =
    list $ list $ list $ list $ list $
    list $ list $ list $ list $ list (1 :: Integer)

sumNestedList :: Integer
sumNestedList = getSum nestedList

मैं इसे F # में कैसे प्राप्त कर सकता हूं?


1
मुझे F # पर्याप्त नहीं पता है - मुझे नहीं पता कि यह हास्केल के टाइपसेकल्स की तरह कुछ का समर्थन करता है। सबसे खराब स्थिति में, आपको स्पष्ट शब्दकोशों को पास करने में सक्षम होना चाहिए, भले ही वह हास्केल में उतना सुविधाजनक न हो, जहां कंपाइलर आपके लिए सही शब्दकोशों को संक्रमित करता है। ऐसे मामले में F # कोड कुछ ऐसा होगा getSum (dictList (dictList (..... (dictList dictInt)))) nestedListजहां टाइप के प्रकार में dictListमैच की संख्या होती []है nestedList
ची

क्या आप एक REPL पर इस haskell कोड को चलाने योग्य बना सकते हैं?
फ़िलिप कार्वाल्हो

यहां आप जाएं ... repl.it/repls/BlondCoolParallelport
karakfa

F # में टाइप कक्षाएं नहीं हैं ( github.com/fsharp/fslang-suggestions/issues/243 )। मैंने कोशिश की कि संचालक ओवरलोडिंग ट्रिक करे कि थ्योरी काम कर सकती है लेकिन मैं सिर्फ कंपाइलर को क्रैश करने में कामयाब रहा लेकिन शायद आप इस ट्रिक से कुछ बना सकते हैं: stackoverflow.com/a/8376001/418488
एक और मेटाप्रोग्रामर

2
मैं किसी भी यथार्थवादी F # कोडबेस की कल्पना नहीं कर सकता जहाँ आपको इसकी आवश्यकता होगी। ऐसा करने के लिए आपकी प्रेरणा क्या थी? मैं शायद डिज़ाइन को बदल दूंगा ताकि आप इस तरह की स्थिति में न आएं - यह शायद वैसे भी आपके एफ # कोड को बेहतर बना देगा।
टॉमस पेट्रीक

जवाबों:


4

अपडेट करें

मुझे ($)एक सदस्य के बजाय एक ऑपरेटर का उपयोग करके एक सरल संस्करण मिला । Https://stackoverflow.com/a/7224269/4550898 से प्रेरित :

type SumOperations = SumOperations 

let inline getSum b = SumOperations $ b // <-- puting this here avoids defaulting to int

type SumOperations with
    static member inline ($) (SumOperations, x  : int     ) = x 
    static member inline ($) (SumOperations, xl : _   list) = xl |> List.sumBy getSum

बाकी विवरण अभी भी लागू है और यह उपयोगी है ...

मुझे इसे संभव बनाने का एक तरीका मिला:

let inline getSum0< ^t, ^a when (^t or ^a) : (static member Sum : ^a -> int)> a : int = 
    ((^t or ^a) : (static member Sum : ^a -> int) a)

type SumOperations =
    static member inline Sum( x : float   ) = int x
    static member inline Sum( x : int     ) =  x 
    static member inline Sum(lx : _   list) = lx |> List.sumBy getSum0<SumOperations, _>

let inline getSum x = getSum0<SumOperations, _> x

2                  |> getSum |> printfn "%d" // = 2
[ 2 ; 1 ]          |> getSum |> printfn "%d" // = 3
[[2; 3] ; [4; 5] ] |> getSum |> printfn "%d" // = 14

अपना उदाहरण चलाना:

let list v = List.replicate 6 v

1
|> list |> list |> list |> list |> list
|> list |> list |> list |> list |> list
|> getSum |> printfn "%d" // = 60466176

यह सदस्य बाधाओं के साथ SRTP का उपयोग करने पर आधारित है: static member Sumबाधा को Sum उस रिटर्न को भेजने वाले सदस्य के प्रकार की आवश्यकता होती है int। SRTPs का उपयोग करते समय सामान्य कार्य करने की आवश्यकता है inline

वह कठिन हिस्सा नहीं है। कठिन हिस्सा Sumएक मौजूदा प्रकार जैसे " सदस्य " को जोड़ना intऔर Listजिसकी अनुमति नहीं है। लेकिन, हम इसे एक नए प्रकार में जोड़ सकते हैं SumOperationsऔर बाधा में शामिल कर सकते हैं (^t or ^a) जहां ^tहमेशा होने वाला है SumOperations

  • getSum0Sumसदस्य बाधा घोषित करता है और उसे आमंत्रित करता है।
  • getSumSumOperationsपहले प्रकार के पैरामीटर के रूप में पास करता हैgetSum0

static member inline Sum(x : float ) = int xकंपाइलर को जेनरिक डायनामिक फंक्शन कॉल का उपयोग करने के लिए समझाने के लिए लाइन जोड़ी गई और कॉल करते static member inline Sum(x : int )समय डिफ़ॉल्ट नहींList.sumBy

जैसा कि आप देख सकते हैं कि यह थोड़ा जटिल है, वाक्यविन्यास जटिल है और संकलक पर कुछ क्विरक्स के आसपास काम करना आवश्यक था लेकिन अंत में यह संभव था।

इस विधि को अधिक परिभाषाएँ जोड़कर Arrays, tuples, विकल्प, या उनमें से किसी भी संयोजन के साथ काम करने के लिए बढ़ाया जा सकता है SumOperations:

type SumOperations with
    static member inline ($) (SumOperations, lx : _   []  ) = lx |> Array.sumBy getSum
    static member inline ($) (SumOperations, a  : ^a * ^b ) = match a with a, b -> getSum a + getSum b 
    static member inline ($) (SumOperations, ox : _ option) = ox |> Option.map getSum |> Option.defaultValue 0

(Some 3, [| 2 ; 1 |]) |> getSum |> printfn "%d" // = 6

https://dotnetfiddle.net/03rVWT


यह एक महान समाधान है! लेकिन सिर्फ पुनरावृत्ति या गुना क्यों नहीं?
s952163

4
पुनरावृत्ति और गुना अलग-अलग प्रकारों को संभाल नहीं सकते हैं। जब एक सामान्य पुनरावर्ती कार्य तुरंत होता है तो यह मापदंडों के प्रकार को ठीक करता है। इस मामले में हर कॉल करने के लिए Sumएक सरल प्रकार के साथ किया जाता है: Sum<int list list list>, Sum<int list list>, Sum<int list>, Sum<int>
AMieres

2

यहाँ रनटाइम संस्करण है, सभी .net संग्रहों के साथ काम करेगा। हालाँकि, एएमयर के रनटाइम अपवादों और एमीएरेस के उत्तर में कंपाइलर त्रुटियों का आदान-प्रदान 36 गुना अधिक तेज है।

let list v = List.replicate 6 v

let rec getSum (input:IEnumerable) =
    match input with
    | :? IEnumerable<int> as l -> l |> Seq.sum
    | e -> 
        e 
        |> Seq.cast<IEnumerable> // will runtime exception if not nested IEnumerable Types
        |> Seq.sumBy getSum


1 |> list |> list |> list |> list |> list
|> list |> list |> list |> list |> list |> getSum // = 60466176

मानक

|    Method |        Mean |     Error |    StdDev |
|---------- |------------:|----------:|----------:|
| WeirdSumC |    76.09 ms |  0.398 ms |  0.373 ms |
| WeirdSumR | 2,779.98 ms | 22.849 ms | 21.373 ms |

// * Legends *
  Mean   : Arithmetic mean of all measurements
  Error  : Half of 99.9% confidence interval
  StdDev : Standard deviation of all measurements
  1 ms   : 1 Millisecond (0.001 sec)

1
यह अच्छी तरह से काम करता है, हालांकि यह काफी धीमा है: दूसरे समाधान के साथ 1 सेकंड की तुलना में इसे 10 गुना चलाने में 56 सेकंड का समय लगा।
AMieres

प्रभावशाली बेंचमार्किंग! आपने क्या उपयोग किया
15

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.