I am having trouble locating documentation on simple operations in Haskell.
I have a list of lists ( :: [[a]]
) and I need to reverse all of the element lists x
where length x >= 2
.
So far I haven't found anything on:
How to traverse the lists
How would I find the length of the element. There is the length
function I can use, but I haven't got an idea how to use it.
I did find the reverse
function for lists, though I had trouble finding it.
If any help on those individual implementation, it would be greatly appreciated. I can piece them together.
I need to reverse all of the element lists x where
length x >= 2
You can totally ignore the length x >= 2
part, since if the length of a list is 0 or 1, reversing it has no effect: there's no way to tell whether you reversed it or not, so you might as well just reverse all lists, for uniformity.
Given that, this is super simple: you just need to map reverse
over the list of lists, reversing each one in turn:
reverseEach :: [[a]] -> [[a]]
reverseEach = map reverse
> reverseEach [[1,2,3],[4],[5,6,7,8]]
[[3,2,1],[4],[8,7,6,5]]
And as other answers suggest, you can afford to generalize a little bit:
reverseEach :: Functor f => f [a] -> f [a]
reverseEach = fmap reverse
> reverseEach [[1,2,3],[4],[5,6,7,8]]
[[3,2,1],[4],[8,7,6,5]]
how to traverse the lists.
There are several sequence functions, from the more basic fmap
, which maps a single function over a list, to foldr
, which folds a list structure around a binary operation (for summing a list or similar operations) to the sequence
/ traverse
operations, which carry monadic or applicative effects.
How would I find the length of the element. There is the length function I can use, but I haven't got an idea how to use it.
There is a length
function; you use it like any other function. length xs
, where xs
is a list. If you still aren't certain how to do that, I would suggest starting slower with a Haskell tutorial.
And I have this to reverse the list, But i think i have that now.
There is a reverse
function. If you don't want to use the built-in one (or if you want to do it yourself for educational purposes), you could build an efficient reverse function with an accumulator.
reverse' :: [a] -> [a]
reverse' xs = doReverse xs []
where doReverse [] ys = ys
doReverse (x:xs) ys = doReverse xs (x:ys)
Solution:
conditionallyReverse :: [[a]] -> [[a]]
ConditionallyReverse listOfLists= fmap f listOfLists
where
f list
| length list >= 2 = reverse x
| otherwise = x
We apply the function f
to each element of the listOfLists
by supplying f
as the first argument to fmap
and the listOfLists
as the second argument. The function f
transforms a list
based on the condition length list >= 2
. If the condition holds, the list is reversed, otherwise the original list is returned.
Absurd over-generalization:
Every Traversable
instance supports a horrible hack implementing reverse
. There may be a cleaner or more efficient way to do this; I'm not sure.
module Rev where
import Data.Traversable
import Data.Foldable
import Control.Monad.Trans.State.Strict
import Prelude hiding (foldl)
fill :: Traversable t => t b -> [a] -> t a
fill = evalState . traverse go
where
go _ = do
xs <- get
put (drop 1 xs)
return (head xs)
reverseT :: Traversable t => t a -> t a
reverseT xs = fill xs $ foldl (flip (:)) [] xs
reverseAll :: (Functor f, Traversable t) => f (t a) -> f (t a)
reverseAll = fmap reverseT
In terms of folds:
reverse = foldl (\ acc x -> x : acc) []
length = foldl' (\ n _ -> n + 1) 0
map f = foldr (\ x xs -> f x : xs)
letting
mapReverse = map (\ xs -> if length xs >= 2 then reverse xs else xs)
But length
is a costly O(n), and reverse [x] = [x]
. I would use
map reverse [[1,2,3],[4],[]] == [[3,2,1],[4],[]]
where (map reverse) :: [[a]] -> [[a]]
. map reverse
isn't basic enough to justify an own name binding.
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.