功能编程 – 什么是功能语言中的“模式匹配”?

我在阅读函数式编程,我注意到模式匹配在许多文章中被提到作为功能语言的核心功能之一。

有人可以解释一个Java / C / JavaScript开发人员这是什么意思?

理解模式匹配需要解释三个部分:

>代数数据类型。
>什么模式匹配
>为什么它的真棒。

简单的代数数据类型

类ML函数语言允许定义称为“不相交联合”或“代数数据类型”的简单数据类型。这些数据结构是简单的容器,可以递归定义。例如:

type 'a list =
    | Nil
    | Cons of 'a * 'a list

定义了类栈的数据结构。认为它等同于这个C#:

public abstract class List<T>
{
    public class Nil : List<T> { }
    public class Cons : List<T>
    {
        public readonly T Item1;
        public readonly List<T> Item2;
        public Cons(T item1, List<T> item2)
        {
            this.Item1 = item1;
            this.Item2 = item2;
        }
    }
}

因此,Cons和Nil标识符定义了一个简单的类,其中x * y * z * …定义了一个构造函数和一些数据类型。构造函数的参数未命名,它们由位置和数据类型标识。

您可以创建列表类的实例:

let x = Cons(1, Cons(2, Cons(3, Cons(4, Nil))))

其中相同:

Stack<int> x = new Cons(1, new Cons(2, new Cons(3, new Cons(4, new Nil()))));

模式匹配简而言之

模式匹配是一种类型测试。所以,让我们假设我们创建了一个类似上面的堆栈对象,我们可以实现方法来窥视和弹出堆栈如下:

let peek s =
    match s with
    | Cons(hd, tl) -> hd
    | Nil -> failwith "Empty stack"

let pop s =
    match s with
    | Cons(hd, tl) -> tl
    | Nil -> failwith "Empty stack"

上面的方法是等同的(虽然没有这样实现)到以下C#:

public static T Peek<T>(Stack<T> s)
{
    if (s is Stack<T>.Cons)
    {
        T hd = ((Stack<T>.Cons)s).Item1;
        Stack<T> tl = ((Stack<T>.Cons)s).Item2;
        return hd;
    }
    else if (s is Stack<T>.Nil)
        throw new Exception("Empty stack");
    else
        throw new MatchFailureException();
}

public static Stack<T> Pop<T>(Stack<T> s)
{
    if (s is Stack<T>.Cons)
    {
        T hd = ((Stack<T>.Cons)s).Item1;
        Stack<T> tl = ((Stack<T>.Cons)s).Item2;
        return tl;
    }
    else if (s is Stack<T>.Nil)
        throw new Exception("Empty stack");
    else
        throw new MatchFailureException();
}

(几乎总是,ML语言实现模式匹配,没有运行时类型测试或者转换,所以C#代码有点欺骗)让我们用一些手工挥动刷实现细节请:))

数据结构分解简而言之

好吧,让我们回到偷看的方法:

let peek s =
    match s with
    | Cons(hd, tl) -> hd
    | Nil -> failwith "Empty stack"

诀窍是理解hd和tl标识符是变量(errm …因为它们是不可变的,它们不是真正的“变量”,而是“values”;))。如果s的类型是Cons,那么我们将它的值从构造函数中取出并绑定到名为hd和tl的变量。

模式匹配是有用的,因为它允许我们通过其形状而不是其内容来分解数据结构。所以想象如果我们定义一个二叉树如下:

type 'a tree =
    | Node of 'a tree * 'a * 'a tree
    | Nil

我们可以定义一些tree rotations如下:

let rotateLeft = function
    | Node(a, p, Node(b, q, c)) -> Node(Node(a, p, b), q, c)
    | x -> x

let rotateRight = function
    | Node(Node(a, p, b), q, c) -> Node(a, p, Node(b, q, c))
    | x -> x

(let rotateRight = function constructor是语法糖为let rotateRight s = match s with ….)

因此,除了将数据结构绑定到变量之外,我们还可以深入了解它。让我们假设我们有一个节点let x = Node(Nil,1,Nil)。如果我们调用rotateLeft x,我们测试x对第一个模式,不能匹配,因为右孩子具有类型Nil而不是Node。它将移动到下一个模式,x – > x,它将匹配任何输入并返回未修改。

为了比较,我们将上面的方法写在C#中:

public abstract class Tree<T>
{
    public abstract U Match<U>(Func<U> nilFunc, Func<Tree<T>, T, Tree<T>, U> nodeFunc);

    public class Nil : Tree<T>
    {
        public override U Match<U>(Func<U> nilFunc, Func<Tree<T>, T, Tree<T>, U> nodeFunc)
        {
            return nilFunc();
        }
    }

    public class Node : Tree<T>
    {
        readonly Tree<T> Left;
        readonly T Value;
        readonly Tree<T> Right;

        public Node(Tree<T> left, T value, Tree<T> right)
        {
            this.Left = left;
            this.Value = value;
            this.Right = right;
        }

        public override U Match<U>(Func<U> nilFunc, Func<Tree<T>, T, Tree<T>, U> nodeFunc)
        {
            return nodeFunc(Left, Value, Right);
        }
    }

    public static Tree<T> RotateLeft(Tree<T> t)
    {
        return t.Match(
            () => t,
            (l, x, r) => r.Match(
                () => t,
                (rl, rx, rr) => new Node(new Node(l, x, rl), rx, rr))));
    }

    public static Tree<T> RotateRight(Tree<T> t)
    {
        return t.Match(
            () => t,
            (l, x, r) => l.Match(
                () => t,
                (ll, lx, lr) => new Node(ll, lx, new Node(lr, x, r))));
    }
}

认真。

模式匹配真棒

你可以使用visitor pattern来实现与C#中的模式匹配类似的东西,但是它没有那么灵活,因为你不能有效地分解复杂的数据结构。此外,如果使用模式匹配,编译器会告诉你是否省略了一个case。这是多么真棒?

想想如何在C#或者没有模式匹配的语言中实现类似的功能。想想在运行时如何没有测试和强制转换。它肯定不难,只是笨重和笨重。而你没有编译器检查,以确保你已经涵盖了每一种情况。

因此,模式匹配可以帮助您以非常方便,紧凑的语法分解和导航数据结构,它使编译器能够检查代码的逻辑,至少有一点。它真的是一个杀手的功能。

http://stackoverflow.com/questions/2502354/what-is-pattern-matching-in-functional-languages

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:功能编程 – 什么是功能语言中的“模式匹配”?