Haskell currying和模式匹配如何协同工作?

时间:2012-09-30 05:37:03

标签: haskell pattern-matching currying

我是Haskell的新手。我知道函数是curry成为带有一个参数的函数。我不明白的是,在这种情况下,如何实现与多个值的模式匹配。例如:

假设我们有以下完全任意的函数定义:

myFunc :: Int -> Int -> Int
myFunc 0 0 = 0
myFunc 1 1 = 1
myFunc x y = x `someoperation` y

myFunc 0基本上返回部分应用的函数:

partiallyAppliedMyFunc :: Int -> Int
partiallyAppliedMyFunc 0 = 0
partiallyAppliedMyFunc y = 0 `someoperation` y

从而删除了无法匹配的无关模式?或者......这里发生了什么?

1 个答案:

答案 0 :(得分:25)

实际上,这个问题比表面上看起来更微妙,并且需要学习一些关于编译器内部的知识才能真正正确回答。原因是我们理所当然地认为我们可以在多个术语上嵌套模式和模式,而实际上为了编译器的目的,你唯一能做的就是在单个顶级构造函数上进行分支值。因此,编译器的第一个阶段是将嵌套模式(以及多个值上的模式)转换为更简单的模式。例如,一个天真的算法可能会将您的函数转换为以下内容:

myFunc = \x y -> case x of
    0 -> case y of
        0 -> 0
        _ -> x `someoperation` y
    1 -> case y of
        1 -> 1
        _ -> x `someoperation` y
    _ -> x `someoperation` y

你已经可以看到这里有许多不理想的东西:someoperation术语重复了很多次,并且函数在它开始甚至开始case之前都需要两个参数;有关如何改进此问题的讨论,请参阅A Term Pattern-Match Compiler Inspired by Finite Automata Theory

无论如何,在这种形式下,实际上应该更清楚一下currying步骤是如何发生的。我们可以直接替换此表达式中的x来查看myFunc 0的作用:

myFunc 0 = \y -> case 0 of
    0 -> case y of
        0 -> 0
        _ -> 0 `someoperation` y
    1 -> case y of
        1 -> 1
        _ -> 0 `someoperation` y
    _ -> 0 `someoperation` y

由于这仍然是一个lambda,因此不会进一步减少。您可能希望一个足够智能的编译器可以做得更多,但GHC显然不会做更多;如果您想在仅提供一个参数后进行更多计算,则必须更改定义。 (这里有一个时间/空间权衡,正确选择太难以可靠地完成。所以GHC让它在程序员的手中做出这个选择。)例如,你可以明确地写一下

myFunc 0 = \y -> case y of
    0 -> 0
    _ -> 0 `someoperation` y
myFunc 1 = \y -> case y of
    1 -> 1
    _ -> 1 `someoperation` y
myFunc x = \y -> x `someoperation` y

然后myFunc 0将减少到更小的表达式。