Search code examples
haskellfunctional-programminghigher-order-functionsparse-error

Higher order function parameter


Problem with and_ function

"error: Parse error in pattern: f1"

 type Movie = (String, Double, String)

-- movies :: [(String, Double, String)]
movies :: [Movie]
movies = [ ("Green Book", 8.3, "Peter Farrelly")
     , ("Inception", 8.8, "Christopher Nolan")
     , ("Incredibles 2", 7.7, "Brad Bird")
     , ("The Dark Knight", 9.0, "Christopher Nolan")
     ]

imdbAtLeast :: Double -> Movie -> Bool
imdbAtLeast minRank (_, rank, _)
  | rank < minRank = False
  | otherwise      = True

director :: String -> Movie -> Bool
director expDir (_, _, dir)
  | expDir == dir = True
  | otherwise     = False

here is the wrong function

and_ :: (Movie -> Bool) -> (Movie -> Bool) -> Movie -> Bool
and_ (f1 param1) (f2 param2) (_, rank, dir)
  | f1 == director = (f1 param1 dir) && (f2 param2 rank)
  | otherwise      = (f1 param1 rank) && (f2 param2 dir)

here is two test for and_ function

and_ (director "Brad Bird") (imdbAtLeast 7.5) ("Incredibles 2", 7.7, "Brad 
Bird")
and_ (imdbAtLeast 7.5) (director "Brad Bird")  ("Incredibles 2", 7.7, "Brad 
Bird")

Solution

  • Your call to and_ does not see director and "Brad Bird" directly; it gets the function that results from applying director to "Brad Bird" (and similarly for the second argument.

    and_ :: (Movie -> Bool) -> (Movie -> Bool) -> Movie -> Bool
    and_ f1 f2 (_, rank, dir) | ...
    

    The bigger problem is that you can't compare functions for equality. Even assuming director itself was passed as a distinct argument, you can't check if it's the same function referred to by director.

    What you want is to simply apply each of the first two functions to the third function and use && on the results:

    and_ :: (Movie -> Bool) -> (Movie -> Bool) -> Movie -> Bool
    and_ f1 f2 m = f1 m && f2 m
    

    f1 and f2 already "know" which part of the Movie argument they are checking against.