How to express a filter that relies on adjacent items in a list functionally

Several times I wanted to go through the list and select elements that have some property, which also depends, say, on the next element in the list. For a simple example, I have a code that counts how many times the function f changes sign by the specified interval [a,b] . This is pretty obvious in an imperative language such as C:

 for(double x=a; x<=b; x+=(ba)/n){ s*f(x)>0 ? : printf("%e %e\n",x, f(x)), s=sgn(f(x)); } 

In Haskell, my first instinct was to pin the list with its tail, and then apply a filter and extract the elements using fst or something else. But that seems awkward and inefficient, so I helped him turn into a crease:

 signChanges fabn = tail $ foldl (\(x:xs) y -> if (fx*fy)<0 then y:x:xs else x:xs) [a] [a,a+(ba)/n..b] 

In any case, I feel that there is a β€œright” way to do this (as is often the case in Haskell) and that I do not know (or simply did not understand) what it is. Any help on how to express this in a more idiomatic or elegant way would be greatly appreciated, as were tips on how to generally find the β€œright” way to do something.

+4
source share
3 answers

Here is the β€œversion” using paramorphism (not quite the same as the question, but it should illustrate parametrism well), first we need para , as it is not in standard libraries:

 -- paramorphism (generalizes fold) para :: (a -> ([a], b) -> b) -> b -> [a] -> b para phi b = step where step [] = b step (x:xs) = phi x (xs, step xs) 

Using paramorphism is very similar to using a crease, but just like watching a battery, we can see the rest of the input:

 countSignChanges :: [Int] -> Int countSignChanges = para phi 0 where phi x ((y:_),st) = if signum x /= signum y then st+1 else st phi x ([], st) = st demo = countSignChanges [1,2,-3,4,-5,-6] 

The good thing about para compared to the tail clasp is that we can peep the way we want into the rest of the input.

+3
source

Zipping is effective if you start with -O2 when you start combining lists. No need to resort to creases in this case, is one of the significant advantages of Haskell, as it improves modularity.

So zipping is the right way to do this.

+4
source

if you need to calculate the value for the i-th element, but depending on the j-th element of the list, it is better to convert the list to Array , either mutable or immutable.

Thus, you can perform arbitrary calculations based on the index of the current element, either in bend mode or in recursive calls.

+1
source

Source: https://habr.com/ru/post/1438243/


All Articles