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?
CodePudding user response:
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 = (-)