英文:
Is there a simpler way to do this pipeline with languageext?
问题
以下是翻译好的代码部分:
我正在尝试理解如何处理将一个“Either”转换为多个“Either”的函数,以及如何将它们合并成单个流。
以下代码将一个字符串转换为多个数字,对每个数字进行平方运算,并忽略任何错误。对于给定的字符串“1,2,Foo,4”,它会输出1,4,16。
这段代码有效,但我不明白为什么“Bind(SafeSplit)”返回一个具有我需要解引用的“Right”属性的“EitherData”。
private static void ValidationPipelineVersion()
{
var result = Right<Exception, string>("1,2,Foo,4")
.Bind(SafeSplit)
.Bind(numStrs => numStrs.Right.Select(SafeParse))
.Rights() // 现在忽略异常
.Map(num => num * num) // 平方
.Iter(num => WriteLine(num));
}
private static Either<Exception, string[]> SafeSplit(string str)
{
try
{
return str.Split(",");
}
catch (Exception e)
{
return e;
}
}
private static Either<Exception, int> SafeParse(string str)
{
try
{
return int.Parse(str);
}
catch (Exception e)
{
return e;
}
}
英文:
I'm trying to grok how to deal with functions that turn one "Either" into many "Either"s and how you then merge those back into a single stream.
The following turns one string into many numbers, squaring each and ignoring any errors. Given "1,2,Foo,4" it writes out 1,4,16.
It works but I don't understand why Bind(SafeSplit) returns an EitherData which has a Right property I need to dereference.
private static void ValidationPipelineVersion()
{
var result = Right<Exception, string>("1,2,Foo,4")
.Bind(SafeSplit)
.Bind(numStrs => numStrs.Right.Select(SafeParse))
.Rights() // ignore exceptions for now
.Map(num => num * num) // Squared
.Iter(num => WriteLine(num));
}
private static Either<Exception,string[]> SafeSplit(string str)
{
try
{
return str.Split(",");
}
catch (Exception e)
{
return e;
}
}
private static Either<Exception,int> SafeParse(string str)
{
try
{
return int.Parse(str);
}
catch (Exception e)
{
return e;
}
}
答案1
得分: 1
我不明白为什么Bind(SafeSplit)
会返回一个具有Right
属性需要取消引用的EitherData
。
你不必(实际上,我建议不要这样做),但它能够编译,因为LanguageExt库带有以下签名的Bind
重载:
public static IEnumerable<R> Bind<T, R>(
this IEnumerable<T> self, Func<T, IEnumerable<R>> binder)
{
return self.BindFast(binder);
}
而且由于Either<L, R>
实现了IEnumerable<EitherData<L, R>>
,所以OP中的代码可以编译。
不建议这样做的原因是因为Right
属性是部分的或不安全的。只要Either
对象是Right
值,它就可以工作,但类型的整个目的是你很少知道是否是这种情况。
这里有一个可能看起来不太简单但至少更安全的替代表达式:
var result = Right<Exception, string>("1,2,Foo,4")
.Bind(SafeSplit)
.Map(numStrs => numStrs
.Map(SafeParse)
.Rights()
.Map(num => num * num) // 平方
.Iter(WriteLine));
它不尝试从单子中获取值,而是保留了外部的Either
容器,并在其中执行所有操作。
英文:
> I don't understand why Bind(SafeSplit) returns an EitherData which has a Right property I need to dereference.
You don't have to (in fact, I'd advise against it), but it compiles because the LanguageExt library comes with a Bind
overload with this signature:
public static IEnumerable<R> Bind<T, R>(
this IEnumerable<T> self, Func<T, IEnumerable<R>> binder)
{
return self.BindFast(binder);
}
and since Either<L, R>
implements IEnumerable<EitherData<L, R>>
the code in the OP compiles.
The reason it's not advisable is because the Right
property is partial or unsafe. It works as long as the Either
object is a Right
value, but the whole point of the type is that you rarely know whether or not that's the case.
Here's an alternative expression that may not look much simpler, but at least is safer:
var result = Right<Exception, string>("1,2,Foo,4")
.Bind(SafeSplit)
.Map(numStrs => numStrs
.Map(SafeParse)
.Rights()
.Map(num => num * num) // Square
.Iter(WriteLine));
Instead of trying to get the value out of the monad, it keeps the outer Either
container and performs all actions inside of it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论