Reputation: 629
If I had a known list A :: [Int]
, and wanted to get a new list B = newList A
with newList
defined as the following:
newList :: [Int] -> [Int]
newList [] = []
newList (a:as) | a==0 = f(a) : newList (as)
| a==1 = g(a) : newList (as)
| otherwise = h(a) : newList (as)
where f, g, h :: Int -> Int
are unimportant functions.
Other than B
, I also wanted to know how many 0, 1
are there in A
respectively.
But since when producing B
recursively, it has already checked whether a== (0 or 1)
for each elements in A
, so it's a redundancy to check it again separably.
Is it possible to get B
but at the same time get how many 0, 1
are there in A
with checking only once?
Upvotes: 2
Views: 113
Reputation: 12715
This is not an answer you are looking for, but there is a nice abstract structure behind your function, so I'll leave it here:
import Data.Monoid
import Data.Functor
import Data.Traversable
import Control.Arrow
import Control.Monad.Trans.Writer
wr :: Int -> Writer (Sum Int, Sum Int) Int
wr 0 = tell (Sum 1, Sum 0) $> f 0
wr 1 = tell (Sum 0, Sum 1) $> g 1
wr n = return $ h n
collect :: [Int] -> ([Int], (Int, Int))
collect = second (getSum *** getSum) . runWriter . traverse wr
Summing is a monoid, double summing is a monoid, the Writer
monad handles monoids, traverse
maps a list with an effectful function and performs all effects.
This:
f = (+ 1)
g = (+ 2)
h = (+ 3)
main = print $ collect [0, 1, 2, 3, 0, 0, 0, 4, 1]
prints ([1,3,5,6,1,1,1,7,3],(4,2))
— four zeros and two ones.
Upvotes: 4