Is there any way to compare two functions in Haskell?
My thought is that the answer is no since functions would not derive the Eq type class. However I'm trying to write a pretty trivial function and it seems like a normal sort of thing to do:
search :: ((Enum a) => a -> a) -> Card -> [Card]
search op x list = if (op == succ && rank x == King) ||
(op == pred && rank x == Ace)
then []
else let c = [ n | n <- list, rank n == op (rank x)]
in if length c == 1
then x : search op (head c) list
else []
Error message:
No instance for (Eq (Rank -> Rank))
arising from a use of `=='
Basically it either searches up or down a list of cards looking for a match with either the next or previous ranked card from x, building a list. By taking the 'pred' or 'succ' function as an operator it works both forwards and backwards. However, I need to check that it doesn't go out of bounds on the enum otherwise it throws an exception.
So I'm looking for a way to prevent the exception or solve this problem!
Any other pointers on improving the code would also be appreciated :)
Thanks for all the great tips, this is the solution I have come up with (taken bits from every answer really!):
EDIT: Correct solution below:
maybeSucc x | x == maxBound = Nothing
| otherwise = Just (succ x)
maybePred x | x == minBound = Nothing
| otherwise = Just (pred x)
-- takes a list of cards which have a rank one op than x
-- only if there is exactly one is it sequential, otherwise end matching
search :: (Rank -> Maybe Rank) -> Rank -> [Card] -> [Card]
search op x list = case filter (\n -> Just (rank n) == op x) list of
[y] -> y : search op (rank y) list
_ -> []
Test:
*Main> let cards = [Card Ace Heart, Card Two Club, Card Three Spade, Card Five Club, Card Four Diamond]
*Main> search maybeSucc Two cards
[Three of Spades,Four of Diamonds,Five of Clubs]
*Main> search maybePred Three cards
[Two of Clubs,Ace of Hearts]
Equality is defined to hold when all three of these parts of two functions are respectively equal. That means that any two functions can be compared for equality. Most notably, in Haskell, functions are not in the Eq typeclass (in general). Not any two functions can be compared for equality in Haskell.
In Haskell let, binding is used to bind the variables, which are very local. In Haskell, we can define any type of variable using let keyword before the variable name in Haskell. But their scope is local, we also have let in Haskell which is another form of defining the variable and use them after it.
The Eq class defines equality ( == ) and inequality ( /= ). All the basic datatypes exported by the Prelude are instances of Eq , and Eq may be derived for any datatype whose constituents are also instances of Eq . The Haskell Report defines no laws for Eq .
Haskell guards are used to test the properties of an expression; it might look like an if-else statement from a beginner's view, but they function very differently. Haskell guards can be simpler and easier to read than pattern matching .
As long as the functions are over appropriate domains and ranges (Enum, Bounded, Eq, etc., in slightly different combination for domain and range), you can compare finite functions, even higher-order ones, in a straight-forward way and then automate the process using type classes.
I wrote up the idea in a post to the one of the Haskell mailing lists and then (more properly) in a paper I presented at one of the FDPE conferences (Victoria, BC). I've never seen it done before, but I wouldn't be surprised if others have also done it: it's a pretty simple idea, once you get over the bugaboo that "functions can't be compared for equality". Of course, the usual caveats about partiality and strictness apply: e.g., you can't return True for two functions that both fail to terminate for some common argument.
But for finite domains this technique works and provides a lot of practical use. (Plus it's really just fun to use :) ).
Edit: I added the code to hpaste here; it works in Hugs, but needs some tweaks for GHC.
Edit 2: I added a pragma and comment to the hpaste-d code so that it works in both GHC and Hugs. I also added this example as test3 (it returns True, as expected, and in short order):
(\x -> [(&&x), (||x), not]) == (\y -> [(y&&), (y||), not . not . not])
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