मैं हर चीज के लिए नया हूं - एफ #, सामान्य रूप से प्रोग्रामिंग, और यह समुदाय। मैं एक गणितज्ञ हूं, जो मेरे स्नातक स्तर पर कंप्यूटर विज्ञान के बारे में संक्षिप्त जानकारी रखता है। मैं F# में कुछ कार्यों को पूरा करने का प्रयास कर रहा हूं और "F# Cheat Sheet" प्रदर्शित करता है कि क्या दिखाई देता है दोहराव की व्याख्या किए बिना कार्यों को लिखने के तीन अलग-अलग तरीके हो सकते हैं। मेरा मतलब देखने के लिए लिंक से प्रासंगिक जानकारी यहां दी गई है।

let कीवर्ड नामित कार्यों को भी परिभाषित करता है।

let negate x = x * -1 
let square x = x * x 
let print x = printfn "The number is: %d" x

let squareNegateThenPrint x = 
print (negate (square x)) 

पाइप ऑपरेटर |> कार्यों और तर्कों को एक साथ जोड़ने के लिए उपयोग किया जाता है। डबल-बैकटिक पहचानकर्ता विशेष रूप से इकाई परीक्षण में पठनीयता में सुधार करने में आसान होते हैं:

let ``square, negate, then print`` x = 
    x |> square |> negate |> print

कंपोजीशन ऑपरेटर >> कार्यों को लिखने के लिए उपयोग किया जाता है:

let squareNegateThenPrint' = 
    square >> negate >> print

कार्यों के साथ वीएस एफ # इंटरैक्टिव में निरीक्षण और खेलकर:

  1. स्क्वायरनेगेटफिरप्रिंट x
  2. ``वर्गाकार, नकारात्मक, फिर प्रिंट करें'' x
  3. स्क्वायरनेगेटफिरप्रिंट'

ऐसा प्रतीत होता है कि यह एक ही चीज़ को पूरा करने के 3 तरीकों की एक सूची है, क्या यहां कोई बारीकियां हैं? मुझे विश्वास है कि एक ही इंट को देखते हुए वे सभी एक ही इंट वापस कर देंगे, लेकिन उससे आगे कैसे? मैं क्या नहीं देख रहा हूँ? तीन विधियों में से प्रत्येक के फायदे और नुकसान क्या हैं?

2 और 3 दोनों 'ऑपरेटर' का उपयोग करते हैं और 1 पुराने कार्यों से एक नया कार्य करने के लिए कार्यों को लिखने का सामान्य 'गणितीय' तरीका प्रतीत होता है। मुझे संदेह है कि विकल्प 3 वास्तव में 1 के बराबर है (इस अर्थ में कि >> ऑपरेटर को परिभाषित किया गया है ताकि square >> negate >> print की गणना वास्तव में print (negate (square x)) के रूप में की जाए, लेकिन कोड को पठनीयता में लाभ मिलता है क्योंकि आप देखते हैं सामान्य गणितीय संकेतन के साथ उल्टे क्रम के बजाय फ़ंक्शन नाम क्रम में होते हैं, और इस तरह से परिभाषित करने से आपको एक या दो कीस्ट्रोक की बचत होती है क्योंकि आपको फ़ंक्शन नाम के अंत में x शामिल करने की आवश्यकता नहीं होती है। >> ऑपरेटर संभवत: बाएं फ़ंक्शन को चर के स्पष्ट संदर्भ के बिना, दाईं ओर फ़ंक्शन के चर पर निर्भरता को स्वचालित रूप से विरासत में देता है।

लेकिन फिर पाइपिंग विधि इसमें कैसे खेलती है? क्या पाइपिंग ऑपरेटर एक अधिक सामान्य ऑपरेटर है जो फ़ंक्शन संरचना के लिए काम करने के लिए ऐसा ही होता है?

साथ ही, मैंने Google पर काफी कुछ किया और पोस्ट करने से पहले दस्तावेज़ीकरण पढ़ने की कोशिश की लेकिन मुझे कहीं भी नहीं मिल रहा था। मुझे यकीन है कि अगर मैं बस आगे बढ़ गया और भाषा सीखता रहा, तो अगले साल किसी समय मैं मतभेदों को समझूंगा। लेकिन मुझे यह भी विश्वास है कि यहां पर कोई व्यक्ति उस प्रक्रिया को तेज कर सकता है और समझा सकता है या कुछ अच्छे उदाहरण प्रदान कर सकता है। अंत में, मैं सी #, या वास्तव में किसी भी अन्य भाषा (गणित को छोड़कर) में कुशल नहीं हूं, इसलिए कुल नोब के लिए स्पष्टीकरण और न केवल एफ # नोब की सराहना की। धन्यवाद!

f#
21
Prince M 1 अगस्त 2018, 21:56
8
एक उम्दा सवाल! :)
 – 
Curt Nichols
1 अगस्त 2018, 23:08
2
निकोलस दो महीने बाद मुझे आखिरकार एहसास हुआ कि यह एक वाक्य था!
 – 
Prince M
20 सितंबर 2018, 04:07

2 जवाब

सबसे बढ़िया उत्तर

सबसे पहले - हां, ये सभी तरीके "तार्किक रूप से" और हार्डवेयर में संकलित होने पर दोनों के बराबर हैं। ऐसा इसलिए है क्योंकि |> और >> ऑपरेटरों को inline के रूप में परिभाषित किया गया है। परिभाषा मोटे तौर पर इस तरह दिखती है:

let inline (|>) x f = f x
let inline (>>) f g = fun x -> g (f x)

inline कीवर्ड का अर्थ यह है कि कंपाइलर फ़ंक्शन के कॉल को फ़ंक्शन के मुख्य भाग से बदल देगा, और फिर परिणाम संकलित करेगा। इसलिए, निम्नलिखित दोनों:

x |> f |> g
(f >> g) x

निम्नलिखित की तरह ही बिल्कुल संकलित किया जाएगा:

g (f x)

व्यवहार में, हालांकि, गठिया होते हैं।


एक गोचा टाइप अनुमान और कक्षाओं/इंटरफेस के साथ इसके इंटरप्ले के साथ है। निम्न पर विचार करें:

let b = "abcd" |> (fun x -> x.Length)
let a = (fun x -> x.Length) "abcd"

भले ही ये परिभाषाएँ तार्किक और संकलित दोनों रूप में समतुल्य हैं, फिर भी पहली परिभाषा संकलित होगी, और दूसरी नहीं। ऐसा इसलिए होता है क्योंकि एफ # में टाइप अनुमान बिना डबलबैक के बाएं से दाएं आगे बढ़ता है, और इसलिए, पहली परिभाषा में, जब तक कंपाइलर x.Length तक पहुंच जाता है, तब तक यह पहले से ही जानता है कि x एक string, ताकि यह सदस्य लुकअप को सही ढंग से हल कर सके। दूसरे उदाहरण में, कंपाइलर नहीं जानता कि x क्या है, क्योंकि उसे अभी तक "abcd" तर्क का सामना नहीं करना पड़ा है।


एक और गोचा खतरनाक मूल्य प्रतिबंध से संबंधित है। सरल शब्दों में यह कहता है कि एक परिभाषा जो वाक्यविन्यास है (तार्किक रूप से नहीं!) एक मान (एक फ़ंक्शन के विपरीत) सामान्य नहीं हो सकती है। इसमें अस्पष्ट कारण हैं जो उत्परिवर्तन के साथ करना है - स्पष्टीकरण के लिए लिंक किए गए आलेख को देखें।

इसे कार्य संरचना पर लागू करते हुए, निम्नलिखित कोड पर विचार करें (ध्यान दें कि f और g दोनों सामान्य कार्य हैं):

let f x = [x]
let g y = [y]

let h1 = f >> g
let h2 x = x |> f |> g

यहां, h2 ठीक संकलित करेगा, लेकिन h1 मूल्य प्रतिबंध के बारे में शिकायत नहीं करेगा।


व्यवहार में, इन तीन तरीकों के बीच चयन आमतौर पर पठनीयता और सुविधा के लिए होता है। इनमें से कोई भी स्वाभाविक रूप से दूसरों से बेहतर नहीं है। जैसे ही मैं कोड लिखता हूं, मैं आमतौर पर अपने स्वाद के आधार पर चुनता हूं।

24
Fyodor Soikin 1 अगस्त 2018, 22:19
आपके उत्तर के लिए धन्यवाद एक टन! क्या मैं सही हूं कि 'मजेदार' कीवर्ड एक अनाम फ़ंक्शन को परिभाषित करने का एक तरीका है? यानी जब आप 'फन' लिखते हैं तो इसका मतलब होता है 'इसके बाद जो चीज आती है वह एक फंक्शन है, लेकिन मुझे इसे स्टोर करने या इसे कोई नाम देने की जरूरत नहीं है'?
 – 
Prince M
1 अगस्त 2018, 23:09
2
हाँ, बिल्कुल। साथ ही, अगर आप बहुत नए हैं, तो मैं fsharpforfunandprofit.com की सलाह देता हूं - शुरुआती लोगों के लिए बहुत सारी अच्छी जानकारी।
 – 
Fyodor Soikin
1 अगस्त 2018, 23:32
जब मैं Google सामान करता हूं तो वह साइट बहुत ऊपर आती है। धन्यवाद, मैं इसे ध्यान में रखूंगा
 – 
Prince M
2 अगस्त 2018, 01:23
हमेशा की तरह बहुत अच्छा जवाब। हाल ही में गोचा 1 ने मुझे काफी परेशान किया, लेकिन मेरे साथ ऐसा कभी नहीं हुआ कि आप इस समस्या को अपने तरीके से हल कर सकते हैं!
 – 
sebhofer
3 अगस्त 2018, 21:58
खुशी है कि मैं @sebhofer . की मदद कर सका
 – 
Fyodor Soikin
4 अगस्त 2018, 04:43

ये सभी मूल रूप से समकक्ष अवधारणाएं हैं जिनका उपयोग विभिन्न परिस्थितियों में किया जाता है। कोई सही या गलत तरीका नहीं है जो सार्वभौमिक रूप से लागू होगा, लेकिन ऐसे समय होते हैं जब आप पाइपलाइनिंग और संरचना ऑपरेटरों का लाभ उठा सकते हैं जो अभ्यास के माध्यम से स्पष्ट हो जाते हैं और एफ # प्रोग्रामिंग पैटर्न के अधिक जोखिम के माध्यम से स्पष्ट हो जाते हैं।

कुछ उदाहरण देने के लिए, अनुक्रमों के साथ काम करते समय अक्सर पाइपलाइनिंग का उपयोग किया जाता है, क्योंकि यह संचालन की बहुत लंबी श्रृंखलाओं को एक साथ पढ़ने योग्य तरीके से बनाने की अनुमति देता है जो एक धाराप्रवाह-शैली क्वेरी सिंटैक्स की तरह दिखता है।

[0..100]
|> List.filter (fun x -> x % 2 = 0)
|> List.map (fun x -> x / 2)
|> List.sum

हममें से कई लोगों के लिए जो हर समय F# का उपयोग करते हैं, यह List.sum (List.map (fun x -> x / 2) (List.filter (fun x -> x % 2 = 0) [0..100])) जैसी किसी चीज़ से कहीं अधिक पठनीय है।

bind जैसे उच्च-क्रम के कार्यों के साथ काम करते समय अक्सर संरचना का उपयोग किया जाता है। उदाहरण के लिए:

[0..5] 
|> List.tryFind (fun x -> x = 3) 
|> Option.bind ((*) 3 >> Some)

यहां, हम एक सूची में tryFind करने के लिए पाइपलाइन का उपयोग कर रहे हैं और Option टाइप करने के लिए यह Option.bind पर वापस आ जाता है, जो हस्ताक्षर int -> Option 'b के साथ एक फ़ंक्शन लेता है, लेकिन यदि हमारे पास पहले से कोई फ़ंक्शन int -> int (जैसे गुणा) है तो हम >> का उपयोग करके उस फ़ंक्शन को Some के साथ बना सकते हैं और कंपोज़ किए गए फ़ंक्शन को bind पर पास कर सकते हैं। ((*) 3 आंशिक रूप से 3 को गुणन फ़ंक्शन में लागू करने के लिए केवल F# सिंटैक्स है, एक ऐसा फ़ंक्शन लौटाता है जो किसी भी पूर्णांक को 3 से गुणा करता है)।

हम Option.bind (fun x -> Some (x * 3)) लिखकर एक ही चीज़ हासिल कर सकते हैं, लेकिन >> ऑपरेटर और आंशिक-एप्लिकेशन सिंटैक्स हमें कुछ कीस्ट्रोक्स बचाते हैं।

6
Aaron M. Eshbach 1 अगस्त 2018, 22:11
(खुशी है कि मैं आप दोनों को एक साथ वापस ला सकता हूं।) आपके उत्तर हारून के लिए धन्यवाद, संदर्भ विशिष्ट वरीयता और उपयोगकर्ता विशिष्ट वरीयता के अच्छे उदाहरण।
 – 
Prince M
1 अगस्त 2018, 23:17