Haw Haw
Haw Haw

Reputation: 113

How to combine constraints

I need to write a function that takes in two constraints and returns a third constraint that is satisfied only if the first two are also satisfied. I could write a helper function that tests if the first two constraints return true or false, but the problem is that the test could be anything so I can't just pass in something in order to test it. Is there a way to somehow combine two functions/constraints of any type?

I hope I'm making sense.

Upvotes: 0

Views: 525

Answers (3)

Dan Burton
Dan Burton

Reputation: 53665

Obligatory cryptic answer:

import Control.Arrow
import Data.Composition

both :: (a -> Bool) -> (a -> Bool) -> a -> Bool
both = uncurry (&&) .** (&&&)

Someday I'll get around to documenting my Data.Composition library properly (it's on hackage!), but basically (.**) f g x y z = f (g x y z)

Here's how it works (simplified how &&& works on functions)

(&&&) f g x = (f x, g x)
uncurry f (x,y) = f x y
(.**) f g x y z = f (g x y z)

both = uncurry (&&) .** (&&&)
-- undo infix notation
both = (.**) (uncurry (&&)) (&&&)
-- definition of .**, with f = (uncurry (&&)), g = (&&&), x = p1, y = p2, z = v
both = \p1 p2 v -> (uncurry (&&)) ((&&&) p1 p2 v) 
-- definition of &&&, with f = p1, g = p2, x = v
both = \p1 p2 v -> (uncurry (&&)) (p1 v, p2 v)
-- definition of uncurry, with f = (&&)
both = \p1 p2 v -> (\(x, y) -> (&&) x y) (p1 v, p2 v)
-- function application, bind x = p1 v, y = pw v
both = \p1 p2 v -> (&&) (p1 v) (p2 v)
-- rewrite without lambda, move && to infix position
both p1 p2 v = p1 v && p2 v

We have now arrived at hammar's definition. :)

Upvotes: 3

Thomas M. DuBuisson
Thomas M. DuBuisson

Reputation: 64740

If you have two tests of type:

constraint1 :: a -> Bool
constraint2 :: b -> Bool

And you wish to build a third constriant that is the union of the two, then just use (&&):

constraint3 :: a -> b -> Bool
constraint3 a b = constraint1 a && constraint2 b

Upvotes: 0

hammar
hammar

Reputation: 139840

Assuming that by "constraint" you mean some sort of predicate, you can easily write a function which combines two predicates to make a new predicate.

type Pred a = a -> Bool

both :: Pred a -> Pred a -> Pred a
both p1 p2 x = p1 x && p2 x

A quick test run:

*Main Data.Char> both odd (> 3) 5
True
*Main Data.Char> both isAlpha isUpper 'b'
False

Upvotes: 5

Related Questions