0

I want to write a function that checks if two lists are "almost" equal. The first parameter d is used for precision - the difference between the elements must not exceed d.

For example, nearlyEqual 0.5 [2,5] [2.5, 5.1] equals True, but nearlyEqual 0.1 [2,5] [2.5, 5.1] equals False.

I wrote this but it is not working:

nearlyEqual :: Int -> [Int] -> [Int] -> Bool
nearlyEqual d xs ys = foldr(&&) True $ zipWith (\x y -> abs(x-y)<=d)

What am I missing? Any help would be greatly appreciated!

blair
  • 21
  • 4

1 Answers1

4

Not sure if it's a typo, but you're not passing xs and ys to your function.

nearlyEqual d xs ys = foldr(&&) True $ zipWith (\x y -> abs(x-y)<=d)

should be

nearlyEqual d xs ys = foldr(&&) True $ zipWith (\x y -> abs(x-y)<=d) xs ys

at least for it to typecheck.

A clearer implementation would make use of all, which is of type Foldable t => (a -> Bool) -> t a -> Bool, and of the function composition operator (.):

nearlyEqual d xs ys = all ((<= d) . abs) $ zipWith (-) xs ys

where zipWith (-) xs ys is element-wise difference of the two lists, and all verifies that the predicate (<= d) . abs holds for all of the elements of that list; the predicate, given an argument, applies abs to it, and then (<= d) to the result.

chepner
  • 497,756
  • 71
  • 530
  • 681
Enlico
  • 23,259
  • 6
  • 48
  • 102
  • 1
    @blair You are also using both `d` and `e` inconsistently for the tolerance. – chepner Mar 05 '22 at 14:36
  • And a misleading whitespace policy, imho. `foldr(&&)` and `abs(x-y)` makes a lot look like languages where you need parenthesis to enclose the argument(s). – Enlico Mar 05 '22 at 14:44