Reputation: 695
I'm relatively new to haskell and I just recently learned about Applicative Functors and I made this code for xor with only functors and boolean functions. I'm wondering if you guys can come up with a shorter solution (which I'm sure exists) with functors.
xor :: Bool->Bool->Bool
xor=(<$>) (not<$>) ((<*>).((((not<$>)<$>(&&))<$>)<$>((not<$>)<$>(&&)))<*>(||))
I know this probably isn't very good practice; it was more of a brain-teaser for me.
PS I hope this is allowed here
Upvotes: 3
Views: 1935
Reputation: 152682
Here is a solution which you could conceivably write by hand (and read, with a bit of guidance!). As @AJFarmar noted, we can write
xor a b = (a || b) && (not a || not b)
and I will use the rewrite he suggested as well, namely a && b = not (not a || not b)
, though in the opposite direction he did:
xor a b = (a || b) && not (a && b)
You can follow the process below for other definitions, but this one is a particularly short starting definition.
Now we can pick out the chunks a || b
and a && b
and, instead of thinking of them as values of type Bool
in an environment with a :: Bool
and b :: Bool
, transform them into a form where we think of them as values of type Bool
with two Applicative
"context" wrappers. Thus (||) :: f (g Bool)
and (&&) :: f (g Bool)
, where f
and g
are the particular Applicative
instance (->) Bool
. So we are in the partially translated state
xor = (||) && not (&&)
The only problem now is that the infix &&
and the not
expect pure Bool
values, but are being handed doubly-wrapped Bool
s. So we will lift them using double liftA*
applications. Thus:
xor = liftA2 (liftA2 (&&)) (||) (liftA (liftA not) (&&))
There are other ways to spell this, too. I prefer the name (<$>)
to liftA
. Also, one can think of doubly-wrapped Applicative
s as singly wrapped things with a more complicated wrapper, thus:
xor = getCompose (liftA2 (&&) (Compose (||)) (not <$> Compose (&&)))
Upvotes: 9
Reputation: 11913
Okay, this is really pointless and silly, but hey-ho.
First, I defined xor
in terms of &&
, not
and ||
:
xor a b = (a || b) && (not a || not b)
Then if I use the fact that (&&) a b = not (not a || not b)
...
xor a b = not ( not (not a || not b) || not (a || b) )
Which is low-level enough. Then, I ran it through pointfree
to get this:
xor = (not .) . ap (ap . (((||) . not) .) . (. not) . (||) . not) ((not .) . (||))
Now, ap
from Control.Monad
is the monadic equivalent to (<*>)
, and (.)
is (<$>)
in the function monad, so we can replace a few things:
xor = (not<$>)<$>(<*>)((<*>)<$>(((||)<$>not)<$>)<$>(<$>not)<$>(||)<$> not)((not<$>)<$>(||))
And voila, a really ridiculously stupid function that will achieve nothing special! Knock yourself out.
Upvotes: 3