Как монада «Может быть» действует как короткое замыкание?

Я пытаюсь получить более глубокое понимание Монад. Поэтому я начал немного копаться в Монаде Может быть.

Есть одна вещь, которую я просто не могу Кажется, все правильно. Прочтите это:

«Итак, Maybe Bind действует как короткое замыкание. В любой цепочке операций, если какой-либо из них возвращает Nothing, оценка прекращается и Nothing не будет возвращено из всей цепочки ».

From: http://mikehadlow.blogspot.com/2011/01 /monads-in-c-5-maybe.html

И это:

«Для типа Maybe привязка реализуется по простому правилу: если цепочка возвращает пустой значение в какой-то момент, дальнейшие шаги в цепочке игнорируются и вместо этого возвращается пустое значение »

From:« Функциональное программирование на C # » http://www.amazon.com/Functional-Programming-Techniques- Projects-Programmer / dp / 0470744588 /

Хорошо, давайте посмотрим на код. Вот моя монада Maybe:

public class Maybe
{
    public static readonly Maybe Empty = new Maybe(); 

    public Maybe(T value)
    {
        Value = value;
    }

    private Maybe()
    {
    }

    public bool HasValue()
    {
        return !EqualityComparer.Default.Equals(Value, default(T));
    }

    public T Value { get; private set; }

    public Maybe Bind(Func> apply)
    {
        return HasValue() ? apply(Value) : Maybe.Empty;
    }
}

public static class MaybeExtensions
{
    public static Maybe ToMaybe(this T value)
    {
        return new Maybe(value);
    }
}

А вот мой пример кода с использованием монады:

class Program
{
    static void Main(string[] args)
    {
        var node = new Node("1", new Node("2", new Node("3", new Node("4", null))));

        var childNode = node.ChildNode
            .ToMaybe()
            .Bind(x => x.ChildNode.ToMaybe())
            .Bind(x => x.ChildNode.ToMaybe())
            .Bind(x => x.ChildNode.ToMaybe())
            .Bind(x => x.ChildNode.ToMaybe())
            .Bind(x => x.ChildNode.ToMaybe());

        Console.WriteLine(childNode.HasValue() ? childNode.Value.Value : "");

        Console.ReadLine();
    }
}

public class Node
{
    public Node(string value, Node childNode)
    {
        Value = value;
        ChildNode = childNode;
    }

    public string Value { get; set; }
    public Node ChildNode { get; private set; }
}

Ясно, что мы пытаемся покопайтесь в дереве узлов глубже, чем это возможно. Однако я не вижу, как оно действует в соответствии с приведенными мной цитатами. Я имею в виду, конечно, я исключил проверки на null, и пример работает. Однако он не нарушает цепь рано.Если вы установите точки останова, вы увидите, что каждая операция Bind () будет использоваться без значения для последних операций. Но это означает, что если я копаю на 20 уровней глубже, а на самом деле он опускается только на 3 уровня, я все равно проверю 20 уровней, или я ошибаюсь?

Сравните это с немонадным подходом:

        if (node.ChildNode != null
            && node.ChildNode.ChildNode != null
            && node.ChildNode.ChildNode.ChildNode != null)
        {
            Console.WriteLine(node.ChildNode.ChildNode.ChildNode.Value);
        }

Разве это не то, что на самом деле следует назвать короткое замыкание? Потому что в этом случае if действительно прерывается на уровне, где первое значение равно нулю.

Может ли кто-нибудь помочь мне прояснить это?

ОБНОВЛЕНИЕ

Как заметил Патрик, да, это правда, что каждая привязка будет активирована, даже если у нас есть только 3 уровня и мы попытаемся пройти 20 уровней. Однако фактическое выражение, предоставленное вызову Bind (), не будет оцениваться. Мы можем отредактировать пример, чтобы прояснить эффект:

        var childNode = node.ChildNode
            .ToMaybe()
            .Bind(x =>
                      {
                          Console.WriteLine("We will see this");
                          return x.ChildNode.ToMaybe();
                      })
            .Bind(x => x.ChildNode.ToMaybe())
            .Bind(x => x.ChildNode.ToMaybe())
            .Bind(x => x.ChildNode.ToMaybe())
            .Bind(x =>
                      {
                          Console.WriteLine("We won't see this");
                          return x.ChildNode.ToMaybe();
                      });

8
задан Christoph 26 November 2011 в 12:00
поделиться