Search code examples
haskellstring-comparison

compairing inputs in haskell


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)

Solution

  • 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.