3

The elem command allows us to do the following:

elem 1 [1,2,3] = True

elem (Just 4) [(Just 5)] = False

My question is if this is possible to do on math operators.

For example:

elem (+) [(+), (-), div]

It does not seem like it is possible from definition of elem :: (Eq a, Foldable t) => a -> t a -> Bool, and (+) is of Num a => a -> a -> a.

Then how can one test this?

K Split X
  • 3,405
  • 7
  • 24
  • 49
  • 1
    You can't, unless you define an instance of `Eq` for (an appropriate subset of) functions. Good luck if you want to try that :) – Robin Zigmond Mar 29 '19 at 00:11
  • You might also like [How to compare two functions for equivalence](https://stackoverflow.com/q/17045941/791604). – Daniel Wagner Mar 29 '19 at 00:36

2 Answers2

2

Yes, the universe package offers equality checking for total functions on finite domain -- at a price.

Data.Universe.Instances.Reverse Data.Word> elem (+) [(+), (-), (*) :: Word8 -> Word8 -> Word8]
True
Data.Universe.Instances.Reverse Data.Word> elem (+) [(-), (*) :: Word8 -> Word8 -> Word8]
False

What price? Comparison is done by applying the function to all possible inputs and comparing the corresponding outputs. In the case of Word8 there's only about ~60k inputs, so it's feasible to do it before you blink, but don't try that first one on Int -> Int -> Int...

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • That should teach me to make a comment that such a thing effectively can't be done! Clearly it's straightforward (in theory) to actually define the instance if the domain is finite but I'm rather shocked that anyone has actually done it. And there doesn't appear to be a link to the source from there so I can't see if they used any "magic" to make it reasonably quick - although based on your comment I'm guessing they didn't. – Robin Zigmond Mar 29 '19 at 00:32
  • 2
    @RobinZigmond You may see the source of the `Eq` instance [here](http://hackage.haskell.org/package/universe-reverse-instances-1.0/docs/src/Data-Universe-Instances-Eq.html) if you like. No magic beyond the standard laziness to cut off early if possible. – Daniel Wagner Mar 29 '19 at 00:33
  • Thanks, and yeah, that's just the brute force approach (assuming `universeF` is a list of all values of the input type). – Robin Zigmond Mar 29 '19 at 00:35
  • Wow that's horrifying – DarthFennec Mar 29 '19 at 16:18
2

In general, equality of functions is a big can of worms that you don't want to open. However, for numerical operators it is actually quite common to follow the symbolic-manipulation tradition of considering functions not so much as value mappings but as algebraic expressions, and those can in a naïve but not completely unreasonable way be compared efficiently. This requires a suitable symbolic “reflection type”; here with simple-reflect: you could do

{-# LANGUAGE FlexibleInstances #-}
import Debug.SimpleReflect
instance Eq (Expr -> Expr -> Expr) where
  j == k  = j magicL magicR == k magicL magicR
   where magicL = 6837629875629876529923867
         magicR = 9825763982763958726923876

main = print $ (+) `elem` [(+), (*), div :: Expr->Expr->Expr]

This is still a heuristic which might yield false positives, but it does work for your example and also for more involved ones. Note however that it does not consider arithmetic laws in any way, so it will give e.g. (+) /= flip (+).

I would recommend to try to solve your problem in a way that doesn't require equality of Haskell functions.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319