I'm just looking to make general improvements to my Haskell code, and was wondering if the following function could be made point-free? Mostly for curiosity's sake.
Given two functions which we'd like to use in our filter
:
isZero = (==0)
isOne = (==1)
How would we go about utilising those two functions in our contrived example, but making it point-free?
filter (\x -> isZero x || isOne x) [0..100]
There's a online-service for converting Haskell
code to point-free.
It suggests: filter (liftM2 (||) isZero isOne) [0..100]
liftA2 (||) isZero isOne
or (||) <$> isZero <*> isOne
is also possible
(||) <$> isZero
has type a0 -> Bool -> Bool
and it's the composition of (||)
and isZero
. This composition takes a number (for isZero
) and a boolean (as another argument for (||)
)
So, it's the same as \\xy -> (||) (isZero x) y
The function type is an instance of Applicative Functor
and we can look at its implementation:
instance Applicative ((->) r) where
pure x = (\_ -> x)
f <*> g = \x -> f x (g x)
So, (||) <$> isZero <*> isOne
is the same as \\x -> ((||) <$> isZero) x (isOne x)
and the same as \\x -> (||) (isZero x) (isOne x)
Thus, if there's zx = y (fx) (gx)
, it can be transformed into point free: z = y <$> f <*> g
An alternate point-free form would be to use the a -> Any
monoid:
λ import Data.Monoid (Any(..))
λ :t getAny . (Any . isZero <> Any . isOne)
getAny . (Any . isZero <> Any . isOne)
:: (Num a, Eq a) => a -> Bool
λ filter (getAny . (Any . isZero <> Any . isOne)) [0..100]
[0,1]
It's a bit longer than the Applicative
solution, but I think it's a little easier to follow when you have more conditions to combine. Compare
getAny . (Any . isZero <> Any . isOne <> Any . isSquare <> Any . isPrime)
or
getAny . foldMap (Any .) [isZero, isOne, isSquare, isPrime]
and
liftA2 (||) (liftA2 (||) (liftA2 (||) isZero isOne) isSquare) isPrime
or
liftA2 (||) isZero $ liftA2 (||) isOne $ liftA2 (||) isSquare isPrime
Though to be honest, if I had lots of these to do, I'd be tempted to define <||> = liftA2 (||)
and do
isZero <||> isOne <||> isSquare <||> isPrime
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.