For example I have a function in haskell:
foo :: Int a => (a -> a -> b) -> a -> b
I want to pattern match by the first argument:
foo (+) a = a + a
foo (-) a = a - a
However, this code causes a compiler error. I tried to use guards, but it didn't help too. Is it possible to implement such pattern matching?
Is it possible to pattern match by function in Haskell?
No. It is one of the consequences of Rice's theorem [wiki] that it is impossible to determine in general if two functions are equivalent. This thus means that it is possible to construct a function that can add two numbers together, but it is impossible for the compiler to proof that that function is equivalent to (+).
If we would use reference equality, then \x y -> x + y should not match with the pattern whereas passing (+) directly would match. This would be rather bizar. Imagine that you have a function f 0 = abs, or f 0 x = abs x. It would be quite strange that a (small) implementation detail of a function could determine the behavior of another function.
The function definition is hower correct (tested this on a GHC 9.0.1 and 8.6.5). It however will not check if the function is (+): you define a variable named (+) that you can use in the body of the function. You can use it as an infix operator, like x + y, or as (+) x y. But the function definition is identical to:
foo :: (a -> a -> b) -> a -> a -> b
foo g x y = g x y
or
foo :: (a -> a -> b) -> a -> a -> b
foo g x y = x `g` y
If you turn the -Wname-shadowing warning on, it will throw a warning that you have a temporary variable that clashes with a variable from a context above:
ghci> f (+) x y = x + y
<interactive>:1:3: warning: [-Wname-shadowing]
This binding for ‘+’ shadows the existing binding
imported from ‘Prelude’ (and originally defined in ‘GHC.Num’)
The signature of your function probably causes that much errors, the signature here should be:
f :: (a -> b -> c) -> a -> b -> c
f (+) x y = x + y
but again, this will not match with the (+) function defined in the Prelude.
If you need some parameter to determine a function, you can - as @RobinZigmond says - make a type that represents certain functions, for example:
data FunctionSelector = Add | Sub
foo :: Num a => FunctionSelector -> a -> a -> a
foo Add = (+)
foo Sub = (-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With