3

我知道标准的方式是

(Eq z) => matchLists :: [x] -> [x] -> Bool
matchLists xs ys = xs == ys

但是我对从外部传递的元素有一个特殊的匹配函数,我无法控制它。

所以我要找的是

matchLists :: (x -> x -> Bool) -> [x] -> [x] -> Bool

(Hoogle说不

你最终会得到一个带有这样签名的自定义函数,还是你会做什么?

编辑:

zip 函数不能满足我的需要,因为结果列表在 2 个输入列表中具有最小长度

编辑:

你觉得这怎么样?

--matchListsWith :: (a -> a -> Bool) -> [a] -> [a] -> Bool
matchListsWith :: (a -> b -> Bool) -> [a] -> [b] -> Bool
matchListsWith _ [] [] = True
matchListsWith _ (_:_) [] = False
matchListsWith _ [] (_:_) = False
matchListsWith matcher (x:xs) (y:ys) = matcher x y && matchListsWith matcher xs ys
4

3 回答 3

5

Using Data.Align we can handle both the zipping and the length issues at once

matchWith :: (a -> b -> Bool) -> [a] -> [b] -> Bool
matchWith f as bs = and $ alignWith combiner as bs where
  combiner = these (const False) (const False) f

This unfolds to the same code as your explicitly recursive function, but using tags from Data.These to mark the various list alignments. It also generalizes to many other structures like Trees or Sequences if you generalize the and.

matchWith :: (Foldable f, Align f) => (a -> b -> Bool) -> f a -> f b -> Bool
matchWith f as bs = Foldable.and $ alignWith combiner as bs where
  combiner = these (const False) (const False) f

data Tree a = Tip | Branch a (Tree a) (Tree a) deriving ( Functor, Foldable )

instance Align Tree where
  nil = Tip
  align Tip Tip = Tip
  align (Branch a la ra) Tip = Branch (This a) (fmap This la) (fmap This ra)
  align Tip (Branch b lb rb) = Branch (That b) (fmap That lb) (fmap That rb)
  align (Branch a la ra) (Branch b lb rb) =
    Branch (These a b) (align la lb) (align ra rb)

So that we have

λ> matchWith (==) Tip Tip
True
λ> matchWith (==) (Branch 3 Tip Tip) (Branch 3 Tip Tip)
True
λ> matchWith (==) (Branch 3 Tip Tip) (Branch 3 Tip (Branch 3 Tip Tip))
False

(Might as well...)

instance Eq a => Eq (Tree a) where (==) = matchWith (==)
于 2013-11-05T19:02:06.463 回答
4

我认为,手写的方法在这里非常好。如果您还没有使用恰好具有解决此问题的合适函数的库,那么我认为仅仅为了减少三行代码而添加另一个依赖项是不值得的。

不过,您仍然可以剃掉一条线:

matchListWith :: (a -> b -> Bool) -> [a] -> [b] -> Bool
matchListWith f (x:xs) (y:ys) = f x y && matchListWith f xs ys
matchListWith _ []     []     = True
matchListWith _ _      _      = False
于 2013-11-05T19:51:03.697 回答
1

一种可能:

matchList f xs ys = and $ zipWith f xs ys
于 2013-11-05T17:03:11.690 回答