Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C中的monad——为什么绑定实现需要传递函数来返回monad?_C#_Monads - Fatal编程技术网

C# C中的monad——为什么绑定实现需要传递函数来返回monad?

C# C中的monad——为什么绑定实现需要传递函数来返回monad?,c#,monads,C#,Monads,我在C中看到的大多数单子示例都是这样写的: public static Identity<B> Bind<A, B>(this Identity<A> a, Func<A, Identity<B>> func) { return func(a.Value); } 然后,我就可以对Lazy、Task、Maybe等使用相同的func,而不需要依赖于实现IValue的实际类型 P> >首先,考虑构图的概念。我们可以轻松地将合成表示

我在C中看到的大多数单子示例都是这样写的:

public static Identity<B> Bind<A, B>(this Identity<A> a, Func<A, Identity<B>> func) {
    return func(a.Value);
}
然后,我就可以对Lazy、Task、Maybe等使用相同的func,而不需要依赖于实现IValue的实际类型


<> P> >首先,考虑构图的概念。我们可以轻松地将合成表示为对代理的操作:

public static Func<T, V> Compose<T, U, V>(this Func<U, V> f, Func<T, U> g)
{
    return x => f(g(x));
}
不起作用。g返回一个单子,但f接受一个U。我有办法把一个U包装成一个单子,但我没有办法打开它

然而,如果我有一个方法

public static Monad<V> Bind<U, V>(this Monad<U> m, Func<U, Monad<V>> k)
{ whatever }
其中,Unit是一个函数,它接受一个V并返回一个Monad

但是如果g返回一个monad,而f不返回monad,那么f和g就没有组合——不能保证有一种方法可以从monad的实例返回到未包装的类型。也许在某些单子的情况下,总是有-像懒惰。也许有时候会有,比如monad。通常有一种方法可以做到这一点,但并不要求您能够做到这一点

顺便说一句,请注意我们刚刚使用Bind作为瑞士军刀制作了一种新的构图。绑定可以进行任何操作!例如,假设我们对序列monad执行Bind操作,我们在C中对IEnumerable类型调用SelectMany:

static IEnumerable<V> SelectMany<U, V>(this IEnumerable<U> sequence, Func<U, IEnumerable<V>> f)
{
    foreach(U u in sequence)
        foreach(V v in f(u))
            yield return v;
}

高效的?没有。但是Bind/SelectMany没有什么做不到的。如果你真的想,你可以用SelectMany来构建所有的LINQ序列操作符。

你能提供一个链接到这个例子吗?第一个?这是我的。添加了原始问题的链接。您在IValue中定义的绑定实际上是一个映射或提升函数,在C中通常称为select。因此,在函数实际返回相同类型的monad的情况下,绑定在提升上添加的唯一内容是“展平”。“展平”是在Scala中看到它的一种方式。绑定称为flatMap,但是想想Maybe monad:仅使用map,你不能从有值的东西变成无值的东西,所以你不能破坏计算。非常感谢你的回答,但是我还有一个问题。在大多数情况下,我想将函数g从T组合到Monad,将函数f从U组合到V。例如,我想将5添加到Lazy,因此5+是从int到int的函数f,但我有一个Monad Lazy,来自于以前的函数调用。所以解包裹的情况仍然相关,但是为什么我希望5+函数返回一个单子呢?为什么我不能在Bind函数中同时进行解包和重新包装?@AndreyShchekin问题在于,Bind操作并不是为了解决您刚才描述的那种问题而设计的。换一种说法,Bind对于这类问题来说是矫枉过正的。@DanielPratt但是什么是为这个问题设计的呢?在我的例子中,函数不能直接组合,因为我需要了解如何将给定的操作应用于monad的内部值。有人在对您的问题的评论中已经提到了这一点,但您似乎正在寻找一个通常称为map的操作。NET框架称之为Select。请看一看可枚举的类型。选择方法:它几乎与您在问题中给出的绑定类型相同。@AndreyShchekin:我已经更新了我的答案,以回答您的第二个问题。
public static Monad<V> Bind<U, V>(this Monad<U> m, Func<U, Monad<V>> k)
{ whatever }
public static Func<T, Monad<V>> Compose<T, U, V>(this Func<U, Monad<V>> f, Func<T, Monad<U>> g)
{
    return x => Bind(g(x), f);
}
public static Func<T, Monad<V>> Compose<T, U, V>(this Func<U, V> f, Func<T, Monad<U>> g)
{
    return x => Bind(g(x), x=>Unit(f(x)));
}
static IEnumerable<V> SelectMany<U, V>(this IEnumerable<U> sequence, Func<U, IEnumerable<V>> f)
{
    foreach(U u in sequence)
        foreach(V v in f(u))
            yield return v;
}
static IEnumerable<A> Where<A>(this IEnumerable<A> sequence, Func<A, bool> predicate)
{
    foreach(A item in sequence)
        if (predicate(item)) 
            yield return item;
}
static IEnumerable<A> Where<A>(this IEnumerable<A> sequence, Func<A, bool> predicate)
{
    return sequence.SelectMany((A a)=>predicate(a) ? new A[] { a } : new A[] { } );  
}