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]
Tacit programming, also called point-free style, is a programming paradigm in which function definitions do not identify the arguments (or "points") on which they operate. Instead the definitions merely compose other functions, among which are combinators that manipulate the arguments.
Point free style means that the code doesn't explicitly mention it's arguments, even though they exist and are being used. This works in Haskell because of the way functions work.
Function composition is an approach where the result of one function is passed on to the next function, which is passed to another until the final function is executed for the final result. Function compositions can be composed of any number of functions.
Partial application allows us to fix a function's arguments. This lets us derive new functions, with specific behavior, from other, more general functions. Currying transforms a function that accepts multiple arguments “all at once” into a series of function calls, each of which involves only one argument at a time.
Point-free style means that the arguments of the function being defined are not explicitly mentioned, that the function is defined through function composition. and if you want to combine these two functions to one that calculates x*x+1, you can define it "point-full" like this: The point-free alternative would be not to talk about the argument x:
Point free style means that the code doesn't explicitly mention it's arguments, even though they exist and are being used. This works in Haskell because of the way functions work. returns a function that takes one argument, therefore there is no reason to explicit type the argument unless you just want too.
Tacit programming (point-free programming) is a programming paradigm in which a function definition does not include information regarding its arguments, using combinators and function composition [...] instead of variables. Point-free ( sum doesn't have any explicit arguments - it's just a fold with + starting with 0):
The point is a mathematical point ( x above), hence "points-free" notation. The link gives more detail, if you need.
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 \x y -> (||) (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 z x = y (f x) (g x)
, it can be transformed into point free: z = y <$> f <*> g
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With