Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to pattern match by function in Haskell?

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?

like image 881
ricnorr Avatar asked Nov 18 '25 19:11

ricnorr


1 Answers

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 = (-)
like image 192
Willem Van Onsem Avatar answered Nov 21 '25 10:11

Willem Van Onsem



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!