Search code examples
haskellfunctional-programmingcombinatorscombinatory-logic

Defining an alternative Psi combinator in Haskell


I've been working on a simple Leetcode problem in Haskell: Max Count of Pos & Neg Integer:

-- First solution
maximumCount :: [Int] -> Int
maximumCount = liftM2 max (length . filter (> 0)) (length . filter (< 0))

-- Custom combinator that's ALMOST the Psi combinator
-- abcde.a(b(ce)(b(de))
myCombinator :: (c -> c -> d) -> (a -> b -> c) -> a -> a -> b -> d
myCombinator f g x y z = f (g x z) (g y z)

-- Second solution
maximumCount' :: [Int] -> Int
maximumCount' = myCombinator max (length .: filter) (> 0) (< 0)

I haven't been able to find an existing combinator that behaves this way. But I am certain that it can be defined by combining existing combinators. I'm still very new to combinatory logic, so I may be unaware of an existing equivalent or perhaps a methodology for deriving a combinator spelling.

I attempted to write a function to combine arguments for a function such that they would be in the correct shape for the on function, but I was unable to get a proper definition.


Solution

  • It looks like on operating over a reader (->) a, so the following ought to work. Note that I started by lifting the binary operator into the reader and invoking on:

    myCombinator op f = on (liftA2 op) f
    

    and then simplified the result:

    import Control.Applicative
    import Data.Function
    
    myCombinator :: (c -> c -> d) -> (a -> b -> c) -> a -> a -> b -> d
    myCombinator = on . liftA2