Is there a non-recursive way to write this paginate function?

The following function is not part of the Haskell standard libraries, so I wrote it:

paginate _ [] = [] paginate n xs = let (h, t) = splitAt n xs in h : paginate nt 

Then I wanted to rewrite it without explicit recursion, but still easy to understand.

I tried the fix version which does not give very satisfactory results:

 paginate = fix go where go _ _ [] = [] go vn xs = let (h, t) = splitAt n xs in h : vnt 

Are there simpler solutions that use the Prelude functions?

+6
source share
4 answers

When I see such a problem, I like to think about the "form" of the function you want. In this case, you start with a list and compile a list of lists. This is a special case, starting with a single value and creating a list that matches expands . So, if you don't mind importing Data.List , you can neatly write your function with unfoldr .

Let's see how to do this step by step. First, as above, you just need to know about unfoldr and see that it can be applied. Here comes a little experience (for example, reading such answers :)).

Next we look at the unfoldr type:

 Prelude Data.List> :t unfoldr unfoldr :: (b -> Maybe (a, b)) -> b -> [a] 

The idea is that we start with one core value ( b ) and repeatedly apply the step function ( b -> Maybe (a, b) ) until we press Nothing . Our starting value is a list that we want to split into pieces, so we no longer need to deal with processing. This means that the last step we take is the implementation of the step function.

Since we start with a list of values, we can replace b with [n] ; moreover, since we want to create a list of lists at the very end, we can replace [a] with [[n]] and therefore a with [n] . This gives us the final type that we must implement for the step function:

 [n] -> Maybe ([n], [n]) 

Hey, this is very similar to splitAt type!

 splitAt :: Int -> a -> ([a], [a]) 

In fact, we can simply wrap the splitAt result in Just and saturate our types. But this leaves a very important role: the final Nothing , which tells unfoldr to stop! Therefore, our helper function needs an additional base case for [] in order to return the correct result.

Combining everything together, we get the final function:

 import Data.List (unfoldr) paginate n = unfoldr go where go [] = Nothing -- base case go ls = Just (splitAt n ls) 

I think the end result is pretty good, but I'm not sure if it is more readable than the recursive version.

If you don't mind including the extension ( LambdaCase ), you can rewrite this in a slightly more neat way, avoiding the naming of go :

 paginate n = unfoldr $ \case [] -> Nothing ls -> Just (splitAt n ls) 
+14
source

FYI, following from Tikhon Jelvis’s answer, I ended up ending up:

 boolMaybe pfx = if px then Just (fx) else Nothing groupWith = unfoldr . boolMaybe null paginate = groupWith . splitAt 

which is too confusing for me. Back to the recursive version.

+2
source

Here is a slightly modified version of the Tikhon Elvis code:

 import Data.Maybe import Data.List import Control.Applicative paginate n = unfoldr $ \xs -> listToMaybe xs *> Just (splitAt n xs) 

Or in the no space mode:

 paginate n = unfoldr $ (*>) <$> listToMaybe <*> Just . splitAt n 
+2
source

The following has always been:

 import Data.List chunks n = takeWhile (not . null) . unfoldr (Just . splitAt n) 

but the new champion, for me,

 import Data.Maybe -- additional imports import Control.Applicative chunks n = unfoldr $ (<$) . splitAt n <*> listToMaybe -- \xs -> splitAt n xs <$ listToMaybe xs 

(slightly modifying the code from this comment @ user3237465).

The bits used here are:

 unfoldr :: (b -> Maybe (a, b)) -> b -> [a] (f <*> g) x = fx (gx) -- S combinator x <$ c = fmap (const x) c -- "mapped into" listToMaybe xs = head (map Just xs ++ [Nothing]) 

Another similar way of recording is

 import Control.Monad -- an additional import chunks n = unfoldr $ listToMaybe . join ((<$) . splitAt n) -- \xs -> listToMaybe (splitAt n xs <$ xs) 

using monadic join functions for functions,

 join fx = fxx -- W combinator 
0
source

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


All Articles