मुझे यह होमवर्क असाइनमेंट मिला है (होमवर्क टैग नहीं जोड़ा जा सका)। यह सिर्फ एक प्रशिक्षण समस्या है, हाथ में लेने का हिस्सा नहीं है। मैंने एक पुनरावर्ती फ़ंक्शन "eval" बनाया है जो पूर्णांक (+, -, *, /) पर सामान्य संचालन का मूल्यांकन करता है, अब तक, फ़ंक्शन जोड़, गुणा और घटाव का मूल्यांकन कर सकता है।

type expr =
    | Const of int
    | Add of expr * expr
    | Mul of expr * expr
    | Sub of expr * expr

let rec eval (n: expr): int =
    match n with
        | Const n -> n
        | Add (a, b) -> eval a + eval b
        | Mul (a, b) -> eval a * eval b
        | Sub (a, b) -> eval a - eval b

यह फ़ंक्शन पूरी तरह से काम करता है। इसके बाद मुझे विभाजन के लिए अनुमति देने के लिए, expr प्रकार का विस्तार करना होगा:

| Div of expr * expr

इसके अलावा मुझे एक नया प्रकार बनाकर शून्य विभाजन के मामले से निपटने की जरूरत है:

('a, 'b) result

Eval का नया रिटर्न प्रकार कौन सा है (यह असाइनमेंट विवरण में है, इसलिए मुझे यह करना होगा)। यह मेरा प्रयास है:

type ('a, 'b) result =
    | Ok of int
    | Err of string

let rec eval (n: expr): ('a, 'b)result =
    match n with
        | Const n -> Ok(Const n)
        | Add (a, b) -> Ok(eval a + eval b)
        | Mul (a, b) -> OK(eval a * eval b)
        | Sub (a, b) -> Ok(eval a - eval b)
        | Div (_, Const 0) -> Err "zero division"
        | Div (a, b) -> Ok(eval a / eval b)

लेकिन मुझे यह कहते हुए एक त्रुटि मिलती है कि ऑपरेटरों +, -, * और / को प्रकार ('ए,' बी) परिणाम के लिए परिभाषित नहीं किया गया है, जो समझ में आता है। तो मेरा सवाल यह है कि क्या किसी नए प्रकार के अन्य प्रकारों से प्राप्त करने का कोई तरीका है? मैं कुछ ऐसा टाइप नहीं कर सकता:

type ('a, 'b) result =
    | int
    | Err of string

वह बात क्यों नहीं है? क्या मुझे कुछ कीवर्ड निर्दिष्ट करने हैं, इसलिए यदि मैं एक नए प्रकार में int का उपयोग करता हूं, तो int से संबद्ध रहें? एफ # वही आउटपुट प्रकार चाहता है, इनपुट से कोई फर्क नहीं पड़ता, क्या इसके आसपास कोई रास्ता है? क्या मैं फ़ंक्शन को बता सकता हूं कि आउटपुट या तो एक पूर्णांक या एक स्ट्रिंग है, अगर मैंने नया प्रकार नहीं बनाया है?

2
Keinicke 28 अक्टूबर 2020, 20:31

2 जवाब

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

संक्षिप्त उत्तर है नहीं। जैसा आपने कहा था एफ # केवल एक रिटर्न प्रकार की अनुमति देता है।

इस मामले में आपके result प्रकार के मानों के 2 संभावित सेट हैं, Ok मान और Error मान। आपके कोड को दोनों पॉज़िबिलिट्स पर विचार करने की आवश्यकता है, आप एक को अनदेखा नहीं कर सकते। याद रखें eval a अब कोई int नहीं लौटाता, अब यह एक result लौटाता है, जिसके अंदर एक int हो भी सकता है और नहीं भी।

आपके eval a और eval b के बाद लेकिन +, -, * या / को कॉल करने से पहले, आपको यह जांचना होगा कि दोनों में से कोई एक परिणाम है या नहीं Error. यदि दोनों Ok हैं, तभी आप ऑपरेटर को लागू कर सकते हैं। यदि उनमें से कोई एक Error है, तो आपको त्रुटि वापस करनी होगी, है ना?

उदाहरण के लिए, (और int निकालने के लिए) आप match का उपयोग कर सकते हैं:

match eval  a , eval  b  with
|     Ok    a', Ok    b' -> Ok(a' + b')
|     Error e , _    
|     _       , Error e  -> Error e

याद रखें कि आपको ऊपर दिए गए निर्देशों को 4 बार कॉपी करने की आवश्यकता नहीं है। आप एक फ़ंक्शन बना सकते हैं और ऑपरेटर को पैरामीटर के रूप में पास कर सकते हैं इस सिंटैक्स का उपयोग करते हुए: (+), (-), (*), (/)

एक और युक्ति: आप केवल Const 0 से विभाजन के मामले पर विचार कर रहे हैं। यदि आप गणना किए गए 0, उदाहरण के लिए 5/(1 - 1) से विभाजित कर रहे हैं तो क्या होगा?

कार्यात्मक प्रोग्रामिंग में इससे निपटने का एक और तरीका है। अंत में आपको एक Bind फ़ंक्शन (या Apply) की आवश्यकता है। इसके बारे में जानने का एक अच्छा संसाधन यह साइट है: https://fsharpforfunandprofit.com/rop/

1
AMieres 28 अक्टूबर 2020, 22:11

आप पूछ रहे हैं कि क्या एफ # आपको कुछ ऐसा करने की अनुमति देता है:

type Result = int | string

यह एक अनुचित अपेक्षा नहीं है, टाइपस्क्रिप्ट बिल्कुल यही अनुमति देता है। एफ # नहीं, आपने प्रत्येक मामले के लिए एक नया प्रकार परिभाषित किया है।

type Result = Ok of int | Err of string

यह इस मामले में थोड़ा परेशान करता है, दी गई है, लेकिन यह भेदभावपूर्ण यूनियनों को बनाने के लिए इसे और अधिक स्वाभाविक बनाता है - यूनियनों को किसी तरह से "भेदभाव" किया जाता है, यहां उनके प्रकार के नाम से। टाइपस्क्रिप्ट में, आपको प्रत्येक मामले में एक सामान्य संपत्ति जोड़नी होगी, जो कि थोड़ा अनाड़ी है।

मूलभूत अंतर यह है कि F# .NET टाइप सिस्टम पर निर्मित होता है जो नाममात्र का है, और टाइपस्क्रिप्ट एक स्ट्रक्चरल टाइप सिस्टम है। .NET उनके नामों से प्रकारों को अलग करता है, टाइपस्क्रिप्ट उनकी सामग्री द्वारा प्रकारों को अलग करता है। तो आप स्वयं को F# में कुछ और प्रकार के नाम बनाते हुए पाएंगे।

1
Asik 28 अक्टूबर 2020, 21:33