Home > Software design >  Is it possible to pattern match by function in Haskell?
Is it possible to pattern match by function in Haskell?

Time:11-30

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 inGHC.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 = (-)
  • Related