Point equivalent

I have this function from another SO question ,

f :: Ord a => [a] -> [(a, Int)]
f xs = zipWith (\x ys -> (x, length $ filter (< x) ys)) xs (inits xs)

      

I am trying to write it point-free style,

f = flip (zipWith (\x -> (,) x . length . filter (< x))) =<< inits

      

Is it possible to get rid of this x?

+3


source to share


6 answers


As a rule of thumb: if a variable appears more than once in an expression, then it is probably not recommended to do it without dots. If you do decide, the least unreadable way is with combinators Arrow

, because it's pretty clear when the data stream is "split". For xs

I would write

  uncurry (zipWith (...)) . (id &&& inits)

      

For x

, the same method gives



  zipWith ( curry $ uncurry(,) . (fst &&& length . uncurry filter . first(>)) )

      

It's even more than the (->)

-monad solution you used and lambdabot suggests, but looks much more organized.

+6


source


It is possible, but absolutely not worth the pain. To answer your question, LambdaBot tells FreeNode:

f = flip (zipWith (liftM2 (.) (,) ((length .) . filter . flip (<)))) =<< inits

      



At this point, the function lost all clarity and became unattainable. It's much better for you to present real names here. Remember, just because we can make things accurate doesn't mean we have to.

+8


source


The pointfree style point doesn't just omit names for values, but prefers names for functions. This is much easier to do when you use very small definitions. Of course, any code becomes unreadable if you include everything and don't use good names.

So, let's start with your original function and break it down into several smaller definitions.

f xs = zipWith combine xs (inits xs)
combine x xs = (x, countWhere (< x) xs)
countWhere f xs = length (filter f xs)

      

We can now easily make these definitions accurate in a readable way.

f = zipWith combine <*> inits
  where combine = compose (,) countLessThan

compose = liftA2 (.)
countLessThan = countWhere . flip (<)
countWhere = length .: filter
(.:) = (.) . (.)

      

The use of names is smart and the preference for composition over the application allows us to code our code into small, easily understandable definitions. Named parameters are equivalent goto

for data-powerful, but are best used to create higher-level reusable structures that are easier to understand and use correctly. These compositional combinators, such as (.)

and <*>

, are data streams for which map

, filter

and fold

are intended to control flow.

+5


source


My blow to it:

f :: Ord a => [a] -> [(a, Int)]
f = zip <*> ((zipWith $ (length .) . filter . (>)) <*> inits)

      

Here I changed (<)

to (>)

, to have (length .) . filter . (>)

as a function of the arguments in the correct order a->[a]->Int

. Let's move on to zipWith

get it [a]->[[a]]->[Int]

.

Assuming in input [a]

, we can see it as f ([[a]]->[Int])

for Applicative ((->) [a])

, which can be combined with inits :: f [[a]]

with <*> :: f ([[a]]->[Int])->f [[a]]->f [Int]

. This gives us [a]->[Int]

, now we need to consume simultaneously [a]

and [Int]

. zip

already has the correct type: [a]->[Int]->[(a,Int)]

applied with <*>

.

+4


source


Not saying I recommend it, but King Pointfree Control.Arrow

import Control.Arrow

-- A special version of zipWith' more amenable to pointfree style
zipWith' :: ((a, b) -> c) -> ([a], [b]) -> [c]
zipWith' = uncurry . zipWith . curry

f :: Ord a => [a] -> [(a, Int)]
f = zipWith' (fst &&& (length <<< uncurry filter <<< first (>))) <<< id &&& inits

      

Let me clarify here: I really don't recommend this unless you intend to generalize in some way the kind of arrow that your program is running in (like in Arrowized FRP).

+3


source


With a known

 (f .: g) x y = f (g x y)

      

it is semi-readable

zipWith (curry (fst &&& uncurry (length .: (filter . flip (<))) )) <*> inits
--     \(x,ys) -> (x ,           length  ( (filter . flip (<)) x ys) )

      

Using Control.Applicative

( f <*> g $ x = f x (g x)

, combinator S ) and Control.Arrow

(like others, but slightly different).

+2


source







All Articles