我知道标准方式是
(Eq z) => matchLists :: [x] -> [x] -> Bool
matchLists xs ys = xs == ys
但我有一个特殊的元素匹配函数,它从外部传递,我无法控制它。
所以我要找的是
matchLists :: (x -> x -> Bool) -> [x] -> [x] -> Bool
(Hoogle说no)
你最终会得到一个带有这样的签名的自定义函数,或者你会做什么?
修改
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
答案 0 :(得分:5)
使用Data.Align我们可以同时处理压缩和长度问题
matchWith :: (a -> b -> Bool) -> [a] -> [b] -> Bool
matchWith f as bs = and $ alignWith combiner as bs where
combiner = these (const False) (const False) f
这与显式递归函数展开相同的代码,但使用Data.These
中的标记来标记各种列表对齐。如果你概括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)
所以我们有
λ> 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
(也可能......)
instance Eq a => Eq (Tree a) where (==) = matchWith (==)
答案 1 :(得分: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
答案 2 :(得分:1)
一种可能性:
matchList f xs ys = and $ zipWith f xs ys