एक और तकनीक, सीधे कार्यात्मक प्रोग्रामिंग से, निम्नानुसार है। इस तरह की एक आईओ struct को परिभाषित करें:
/// <summary>TODO</summary>
public struct IO<TSource> : IEquatable<IO<TSource>> {
/// <summary>Create a new instance of the class.</summary>
public IO(Func<TSource> functor) : this() { _functor = functor; }
/// <summary>Invokes the internal functor, returning the result.</summary>
public TSource Invoke() => (_functor | Default)();
/// <summary>Returns true exactly when the contained functor is not null.</summary>
public bool HasValue => _functor != null;
X<Func<TSource>> _functor { get; }
static Func<TSource> Default => null;
}
और यह इन विस्तार के तरीकों के साथ एक LINQ करने योग्य इकाई बनाने:
[SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces")]
public static class IO {
public static IO<TSource> ToIO<TSource>(this Func<TSource> source) {
source.ContractedNotNull(nameof(source));
return new IO<TSource>(source);
}
public static IO<TResult> Select<TSource,TResult>(this IO<TSource> @this,
Func<TSource,TResult> projector
) =>
@this.HasValue && projector!=null
? New(() => projector(@this.Invoke()))
: Null<TResult>();
public static IO<TResult> SelectMany<TSource,TResult>(this IO<TSource> @this,
Func<TSource,IO<TResult>> selector
) =>
@this.HasValue && selector!=null
? New(() => selector(@this.Invoke()).Invoke())
: Null<TResult>();
public static IO<TResult> SelectMany<TSource,T,TResult>(this IO<TSource> @this,
Func<TSource, IO<T>> selector,
Func<TSource,T,TResult> projector
) =>
@this.HasValue && selector!=null && projector!=null
? New(() => { var s = @this.Invoke(); return projector(s, selector(s).Invoke()); })
: Null<TResult>();
public static IO<TResult> New<TResult> (Func<TResult> functor) => new IO<TResult>(functor);
private static IO<TResult> Null<TResult>() => new IO<TResult>(null);
}
और अब आप LINQ व्यापक वाक्य रचना इस प्रकार का उपयोग कर सकते हैं:
using Xunit;
[Fact]
public static void IOTest() {
bool isExecuted1 = false;
bool isExecuted2 = false;
bool isExecuted3 = false;
bool isExecuted4 = false;
IO<int> one = new IO<int>(() => { isExecuted1 = true; return 1; });
IO<int> two = new IO<int>(() => { isExecuted2 = true; return 2; });
Func<int, IO<int>> addOne = x => { isExecuted3 = true; return (x + 1).ToIO(); };
Func<int, Func<int, IO<int>>> add = x => y => { isExecuted4 = true; return (x + y).ToIO(); };
var query1 = (from x in one
from y in two
from z in addOne(y)
from _ in "abc".ToIO()
let addOne2 = add(x)
select addOne2(z)
);
Assert.False(isExecuted1); // Laziness.
Assert.False(isExecuted2); // Laziness.
Assert.False(isExecuted3); // Laziness.
Assert.False(isExecuted4); // Laziness.
int lhs = 1 + 2 + 1;
int rhs = query1.Invoke().Invoke();
Assert.Equal(lhs, rhs); // Execution.
Assert.True(isExecuted1);
Assert.True(isExecuted2);
Assert.True(isExecuted3);
Assert.True(isExecuted4);
}
जब कोई आईओ मोनैड चाहता है जो लिखता है लेकिन केवल शून्य देता है, तो इस संरचना को परिभाषित करें और निर्भर करें ईएनटी तरीके:
public struct Unit : IEquatable<Unit>, IComparable<Unit> {
[CLSCompliant(false)]
public static Unit _ { get { return _this; } } static Unit _this = new Unit();
}
public static IO<Unit> ConsoleWrite(object arg) =>
ReturnIOUnit(() => Write(arg));
public static IO<Unit> ConsoleWriteLine(string value) =>
ReturnIOUnit(() => WriteLine(value));
public static IO<ConsoleKeyInfo> ConsoleReadKey() => new IO<ConsoleKeyInfo>(() => ReadKey());
जो आसानी से इस तरह कोड के टुकड़े के लेखन अनुमति देते हैं:
from pass in Enumerable.Range(0, int.MaxValue)
let counter = Readers.Counter(0)
select (from state in gcdStartStates
where _predicate(pass, counter())
select state)
into enumerable
where (from _ in Gcd.Run(enumerable.ToList()).ToIO()
from __ in ConsoleWrite(Prompt(mode))
from c in ConsoleReadKey()
from ___ in ConsoleWriteLine()
select c.KeyChar.ToUpper() == 'Q'
).Invoke()
select 0;
जहां वर्ष सी अल्पविराम ऑपरेटर आसानी से यह क्या है के लिए मान्यता प्राप्त है: एक monadic लिखें ऑपरेशन।
(Enumerable.Range(0,int.MaxValue)
.Select(pass => new {pass, counter = Readers.Counter(0)})
.Select(_ => gcdStartStates.Where(state => _predicate(_.pass,_.counter()))
.Select(state => state)
)
).Where(enumerable =>
((Gcd.Run(enumerable.ToList())).ToIO()
.SelectMany(_ => ConsoleWrite(Prompt(mode)),(_,__) => new {})
.SelectMany(_ => ConsoleReadKey(), (_, c) => new {c})
.SelectMany(_ => ConsoleWriteLine(), (_,__) => _.c.KeyChar.ToUpper() == 'Q')
).Invoke()
).Select(list => 0);
List.Add एक नई सूची वापस नहीं करता है लेकिन सिर्फ यथा-स्थान के लिए उसे संशोधित: जब एक flunt शैली में है कि टुकड़ा लिखने के लिए प्रयास करता है
समझ वाक्य रचना का सच योग्यता स्पष्ट है। इस अर्थ में, यह कार्यात्मक नहीं है। –