比较 haskell 中的输入

compairing inputs in haskell

我确实想获得一个元组 (String, Int) 和另一个值 a 作为我在以下函数中的输入:

getOtherPairValue :: Eq a => (String, Int) -> a -> Either a (b, a)

我想将输入 a 与我的元组进行比较,如果我的元组中的第一个元素与输入 a 不匹配,我想检查它是否与第二个元素匹配。如果它根本不匹配,我确实想要return原样的元组。

如果输入 a 与字符串或整数匹配,我想 return 我的元组的非匹配元素。

我尝试了以下功能:

getOtherPairValue (s, i) e
  | e == i = Left s
  | e == s = Left i
  | e /= s && e /= i = Right (s, i)

在开始之前,让我告诉你,这对我来说是个糟糕的想法。您要求一个函数接受一个参数,该参数必须是字符串或整数,然后是 return“另一种类型”,并且可以处理类型化语言。

我们在 Haskell 中确实有一些东西可以实现类似的东西,但我想知道你是否真的需要首先这样做。

无论如何:

使用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)

注意函数嵌套的 Either return。这是必需的,因为我们必须 return 一个字符串、一个整数或一对。也许 return 自定义总和类型会更明智。

修补类型级机械

这是一个矫枉过正的解决方案。

我们首先定义“元组中的其他类型是什么”

type family Other a where
   Other String = Int
   Other Int    = String

然后,我们使用Typeable在运行时检查类型是否相同:

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

这涉及类型族、GADT 和 Typeable。对我来说,这个操作看起来非常复杂,这种复杂性是由于必须实现一个不能很好地处理类型的函数。