I do want to get a Tuple (String, Int) and another value a as my input in the following function:
getOtherPairValue :: Eq a => (String, Int) -> a -> Either a (b, a)
I want to compare the input a with my tuple and if the first element in my tuple doesn't match with the input a, I want to check if it matches with the second. If it doesn't match at all, I do want to return the Tuple as it is.
If the input a matches with either the string or the integer, I want to return the non matched element of my Tuple.
I tried it with the following function:
getOtherPairValue (s, i) e
| e == i = Left s
| e == s = Left i
| e /= s && e /= i = Right (s, i)
CodePudding user response:
Before starting, let me tell you that this looks like a horrible idea to me. You are asking for a function taking a parameter that must be a string or a integer, then to return "the other type", and that copes with working in a typed language.
We do have something in Haskell that can achieve something similar to that, but I wonder if you really need to do that in the first place.
Anyway:
Use Either
getOtherPairValue :: (String, Int) -> Either String Int
-> Either String (Either Int (String, Int))
getOtherPairValue (s, i) (Left e) | e == s = Right (Left i)
getOtherPairValue (s, i) (Right e) | e == i = Left s
getOtherPairValue p _ = Right (Right p)
Note the nested Either
returned by the function. That's needed since we must return a string, an integer, or a pair. Maybe it would be wise to return a custom sum type instead.
Tinker with type-level machinery
This is an overkill solution.
We first define "what's the other type in the tuple"
type family Other a where
Other String = Int
Other Int = String
Then, we use Typeable
to check at runtime whether the types are the same:
getOtherPairValue :: forall a. Typeable a
=> (String, Int) -> a -> Either (Other a) (String, Int)
getOtherPairValue p@(s, i) x = case (eqT @a @String, eqT @a @Int) of
(Just Refl, _) | x == s -> Left i
(_, Just Refl) | x == i -> Left s
_ -> Right p
This involves type families, GADTs, and Typeable
. To me it looks tremendously complex for this operation, and this complexity is caused by having to implement a function which does not play well with types.