Haskell 中是否可以按函数进行模式匹配?

ric*_*orr 3 haskell compiler-errors

例如我在 haskell 中有一个函数:

foo :: Int a => (a -> a -> b) -> a -> b

我想通过第一个参数进行模式匹配:

foo (+) a = a + a

foo (-) a = a - a

但是,此代码会导致编译器错误。我尝试使用警卫,但也没有帮助。是否可以实现这样的模式匹配?

Wil*_*sem 6

\n

Haskell 中是否可以按函数进行模式匹配?

\n
\n

赖斯定理[wiki]的结果之一是不可能一般地确定两个函数是否等价。因此,这意味着可以构造一个可以将两个数字相加的函数,但编译器不可能证明该函数等同于(+)

\n

如果我们使用引用相等,则\\x y -> x + y不应与模式匹配,而(+)直接传递将匹配。这会比较奇怪。假设您有一个函数f 0 = absf 0 x = abs x。一个函数的(小)实现细节可以决定另一个函数的行为,这将是非常奇怪的。

\n

函数定义是正确的(在 GHC 9.0.1 和 8.6.5 上测试过)。但是,它不会检查该函数是否是(+):您定义了一个名为的变量(+),您可以在函数体内使用该变量。您可以将其用作中缀运算符,例如x + y, 或 as (+) x y。但函数定义与以下相同:

\n
foo :: (a -> a -> b) -> a -> a -> b\nfoo g x y = g x y\n
Run Code Online (Sandbox Code Playgroud)\n

或者

\n
foo :: (a -> a -> b) -> a -> a -> b\nfoo g x y = x `g` y\n
Run Code Online (Sandbox Code Playgroud)\n

如果您打开-Wname-shadowing警告,它将发出警告,提示您有一个临时变量与上面上下文中的变量发生冲突:

\n
ghci> f (+) x y = x + y\n\n<interactive>:1:3: warning: [-Wname-shadowing]\n    This binding for \xe2\x80\x98+\xe2\x80\x99 shadows the existing binding\n      imported from \xe2\x80\x98Prelude\xe2\x80\x99 (and originally defined in \xe2\x80\x98GHC.Num\xe2\x80\x99)\n
Run Code Online (Sandbox Code Playgroud)\n

你的函数的签名可能会导致这么多错误,这里的签名应该是:

\n
f :: (a -> b -> c) -> a -> b -> c\nf (+) x y = x + y\n
Run Code Online (Sandbox Code Playgroud)\n

但同样,这与Prelude 中定义的函数不匹配。(+)

\n

如果您需要一些参数来确定函数,您可以 - 正如@RobinZigmond 所说- 创建一个代表某些函数的类型,例如:

\n
data FunctionSelector = Add | Sub\n\nfoo :: Num a => FunctionSelector -> a -> a -> a\nfoo Add = (+)\nfoo Sub = (-)
Run Code Online (Sandbox Code Playgroud)\n