मैं this F# ROP article का पालन कर रहा हूं, और इसे देखने के लिए मुख्य रूप से यह देखने के लिए सी # में इसे पुन: पेश करने का निर्णय लिया। इस सवाल की लंबाई के लिए माफ़ी, लेकिन यदि आप आरओपी से परिचित हैं, तो इसका पालन करना बहुत आसान होगा।सी # में रेलवे ओरिएंटेड प्रोग्रामिंग - मैं स्विच फ़ंक्शन कैसे लिखूं?
उन्होंने साथ एक एफ # शुरू संघ भेदभाव ...
type Result<'TSuccess, 'TFailure> =
| Success of 'TSuccess
| Failure of 'TFailure
... जो मैं एक सार RopValue वर्ग में अनुवाद किया है, और दो ठोस कार्यान्वयन (ध्यान दें कि मैं लोगों के वर्ग नाम बदल गए हैं कि मैं बेहतर समझा) ...
public abstract class RopValue<TSuccess, TFailure> {
public static RopValue<TSuccess, TFailure> Create<TSuccess, TFailure>(TSuccess input) {
return new Success<TSuccess, TFailure>(input);
}
}
public class Success<TSuccess, TFailure> : RopValue<TSuccess, TFailure> {
public Success(TSuccess value) {
Value = value;
}
public TSuccess Value { get; set; }
}
public class Failure<TSuccess, TFailure> : RopValue<TSuccess, TFailure> {
public Failure(TFailure value) {
Value = value;
}
public TFailure Value { get; set; }
}
मैं तुम्हें एक TSuccess वस्तु है, जो मान्यता कार्यों के पहले में खिलाया जाएगा, जो कि एक RopValue बनाने के लिए अनुमति देने के लिए एक स्थिर बनाने के लिए विधि गयी।
मैं फिर एक बाध्यकारी समारोह लिखने के बारे में गया। एफ # संस्करण निम्नानुसार था ...
let bind switchFunction twoTrackInput =
match twoTrackInput with
| Success s -> switchFunction s
| Failure f -> Failure f
... जो सी # समकक्ष की तुलना में पढ़ने के लिए एक डोडल था! यदि इस लिखने के लिए एक सरल तरीका है, लेकिन यहाँ है कि मैं क्या के साथ आया है मैं नहीं जानता ...
public static RopValue<TSuccess, TFailure> Bind<TSuccess, TFailure>(this RopValue<TSuccess, TFailure> input, Func<RopValue<TSuccess, TFailure>, RopValue<TSuccess, TFailure>> switchFunction) {
if (input is Success<TSuccess, TFailure>) {
return switchFunction(input);
}
return input;
}
ध्यान दें कि मैं एक विस्तार समारोह के रूप में यह लिखा है, कि के रूप में मेरे लिए इसका इस्तेमाल करने की अनुमति दी एक और अधिक कार्यात्मक तरीके से।
एक व्यक्ति को मान्य करने के अपने उपयोग के मामले में लेते हुए, मैं तो एक व्यक्ति वर्ग ...
public class Person {
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
लिखा था ... और एक के साथ मेरी पहली मान्यता समारोह ...
public static RopValue<Person, string> CheckName(RopValue<Person, string> res) {
if (res.IsSuccess()) {
Person person = ((Success<Person, string>)res).Value;
if (string.IsNullOrWhiteSpace(person.Name)) {
return new Failure<Person, string>("No name");
}
return res;
}
return res;
}
लिखा था ईमेल और उम्र के लिए समान सत्यापन के कुछ जोड़े, मैं निम्नानुसार एक सत्यापन प्रमाणीकरण समारोह लिख सकता हूं ...
private static RopValue<Person, string> Validate(Person person) {
return RopValue<Person, string>
.Create<Person, string>(person)
.Bind(CheckName)
.Bind(CheckEmail)
.Bind(CheckAge);
}
यह ठीक काम करता है, और मुझे इस तरह कुछ करने के लिए सक्षम बनाता है ...
Person jim = new Person {Name = "Jim", Email = "", Age = 16};
RopValue<Person, string> jimChk = Validate(jim);
Debug.WriteLine("Jim returned: " + (jimChk.IsSuccess() ? "Success" : "Failure"));
हालांकि, मैं जिस तरह से मैं यह कर दिया है के साथ कुछ मुद्दे हैं। सबसे पहले यह है कि सत्यापन कार्यों के लिए आपको रोपवैल्यू में पास करने की आवश्यकता होती है, सफलता या विफलता के लिए इसे जांचें, अगर सफलता हो, तो व्यक्ति को खींचें और फिर उसे सत्यापित करें। अगर विफलता है, तो बस इसे वापस करें।
इसके विपरीत, उसकी मान्यता कार्यों ले लिया एक व्यक्ति (के बराबर), और लौट आए (एक परिणाम है, जो के बराबर है) एक RopValue ...
let validateNameNotBlank person =
if person.Name = "" then Failure "Name must not be blank"
else Success person
यह बहुत सरल है, लेकिन मैं सी # में यह कैसे करना है यह काम करने में असमर्थ था।
एक और मुद्दा यह है कि हम एक सफलता <> के साथ मान्यता श्रृंखला शुरू करते हैं, इसलिए सबसे पहले मान्यता समारोह हमेशा से कुछ वापस आ जाएगी है "अगर" ब्लॉक, या तो एक विफलता <> यदि सत्यापन विफल हुआ, या एक सफलता <> अगर हम चेक पिछले कर चुके हैं। यदि कोई फ़ंक्शन विफलता <> लौटाता है, तो सत्यापन श्रृंखला में अगला फ़ंक्शन कभी भी नहीं कहा जाता है, इसलिए यह पता चला है कि हम जानते हैं कि इन विधियों को कभी विफल नहीं किया जा सकता है <>।इसलिए, इन कार्यों में से प्रत्येक की अंतिम पंक्ति कभी भी नहीं पहुंच सकती है (अजीब मामले के अलावा, जिसे आपने मैन्युअल रूप से विफलता <> बनाया है और इसे शुरुआत में पास कर दिया है, लेकिन यह व्यर्थ होगा)।
फिर उन्होंने सत्यापन कार्यों को जोड़ने के लिए एक स्विच ऑपरेटर (> =>) बनाया। मैंने ऐसा करने की कोशिश की, लेकिन इसे काम नहीं कर सका। फ़ंक्शन पर लगातार कॉल करने के लिए, ऐसा लगता है कि मुझे एक Func <> पर एक एक्सटेंशन विधि रखना होगा, जो मुझे नहीं लगता कि आप कर सकते हैं। मुझे इस तक मिल गया ...
public static RopValue<TSuccess, TFailure> Switch<TSuccess, TFailure>(this Func<TSuccess, RopValue<TSuccess, TFailure>> switch1, Func<TSuccess, RopValue<TSuccess, TFailure>> switch2, TSuccess input) {
RopValue<TSuccess, TFailure> res1 = switch1(input);
if (res1.IsSuccess()) {
return switch2(((Success<TSuccess, TFailure>)res1).Value);
}
return new Failure<TSuccess, TFailure>(((Failure<TSuccess, TFailure>)res1).Value);
}
... लेकिन इसका उपयोग कैसे किया जा सकता है।
तो, क्या कोई यह समझा सकता है कि मैं बाइंड फ़ंक्शन कैसे लिखूंगा ताकि वह एक व्यक्ति ले सके और रोपवैल्यू (जैसे उसके) को वापस कर सके? मैं एक स्विच फ़ंक्शन कैसे लिखूं जो मुझे सरल सत्यापन कार्यों को जोड़ने की अनुमति देगा?
मेरे कोड पर कोई अन्य टिप्पणी स्वागत है। मुझे यकीन नहीं है कि यह कहीं भी साफ और सरल के रूप में कहीं भी हो सकता है।
यह सब मुझे 'त्रुटि' monad के समान होने पर हमला करता है। क्या आपको लगता है कि यह 'TFailure' प्रकार के साथ प्रभावी रूप से' अपवाद 'के बराबर है? –
Enigmativity
@ मार्क ट्वेन उद्धृत करने के लिए निष्क्रियता, "मैं जल्दी जवाब देने में सक्षम होने से प्रसन्न था, मैंने कहा कि मुझे नहीं पता था!" - मैं एक सी # प्रोग्रामर हूं, एक ही समय में एफ # और कार्यात्मक प्रोग्रामिंग सीख रहा हूं। मैंने मोनैड पर चर्चा की है, लेकिन अभी तक काम नहीं किया है कि वे क्या हैं। –
आपका 'रोपवेल्यू' प्रकार एक मोनड है। मूल रूप से monads सामान्य प्रकार सुपर शक्तियों देते हैं। – Enigmativity