Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Message from discussion Monoids and extending class protocols

Path: g2news1.google.com!postnews.google.com!t54g2000hsg.googlegroups.com!not-for-mail
From: daucl...@gmail.com
Newsgroups: comp.lang.haskell
Subject: Monoids and extending class protocols
Date: Sat, 24 May 2008 21:53:43 -0700 (PDT)
Organization: http://groups.google.com
Lines: 67
Message-ID: <12ccc61e-5495-44c7-a3a9-d8482ba660b6@t54g2000hsg.googlegroups.com>
NNTP-Posting-Host: 72.196.240.248
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
X-Trace: posting.google.com 1211691223 12269 127.0.0.1 (25 May 2008 04:53:43 GMT)
X-Complaints-To: groups-abuse@google.com
NNTP-Posting-Date: Sun, 25 May 2008 04:53:43 +0000 (UTC)
Complaints-To: groups-abuse@google.com
Injection-Info: t54g2000hsg.googlegroups.com; posting-host=72.196.240.248; 
	posting-account=5zctWQoAAAApbE9IYP78UiU8GW_2gnlE
User-Agent: G2/1.0
X-HTTP-UserAgent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; 
	rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14,gzip(gfe),gzip(gfe)

Okay, so I have this generic factorization function, that given an
Integer returns the factors of that Integer in the desired manner:

> factors :: Integer -> (Integer -> Integer -> a -> a) -> a -> a
> factors x adder ans = factors' 2 (x, adder 1 x ans)
>       where factors' test (tot, newans) | test >= tot = newans
>                                         | otherwise   = factors'' (x `divMod` test) test (succ test) (tot, newans)
>             factors'' (newtot, 0) oldtest test (tot, myans) = factors' test (newtot, adder oldtest newtot myans)
>             factors'' _ _ test myans                        = factors' test myans

I don't know if it's the most elegant factorization algorithm in the
universe, but it sure beats the heck out of

> slowfactors x = filter (\y -> x `rem` y == 0) [1..x]

for larger x.

Anyway, when I wish to see what the factors are, I call factors with:

> showfactors :: Integer -> [Integer]
> showfactors x = factors x (\ y z ans -> if y == z then y:ans else y:z:ans) []

and when I simply wish to know the number of factors, I call:

> countfactors :: Integer -> Integer
> countfactors x = factors x (\y z ans -> (if y == z then 1 else 2) + ans) 0

The lambda expressions in these functions are generally adders for
their types, so I should be able to further generalize:

> mkAdder :: Eq a => (a -> b) -> (b -> b -> b) -> a -> a -> (b -> b)
> mkAdder f g y z = g (if y == z then f y else g (f y) (f z))

Which indeed I've done without problems:

> showfactors x = factors x (mkAdder return mplus) []
> countfactors x = factors x (mkAdder (const 1) (+)) 0

But then I noticed the types I'm using ([Integer] and (Sum) Integer)
are Monoidic, so f and g are simply functions under the monoid.  But
then I have a problem -- f is return for the List monad but (const 1)
for the Integer type, and the Monoid doesn't have a return-equivalent,
so I attempted to extend Monoid with one:

> class Monoid a => Monoidic a where
>     mlift :: x -> a

> instance Num a => Monoidic (Sum a) where   -- Monoidic (Sum Integer) didn't work either
>     mlift = const 1

> instance Monoidic [a] where
>     mlift = return

so I could rewrite my mkAdder with the obvious mappend and mlift
functions:

> mkAdder :: (Monoidic b, Eq a) => a -> a -> (b -> b)
> mkAdder y z = mappend (if y == z then mlift y else mappend (mlift y) (mlift z))

This path opened a whole can of (type-checking) worms, which is rather
perplexing for me, as I used the implementation of MonadPlus'
extension to Monad as a guide.

So, how do I rewrite my mkAdder, exploiting the fact that (Sum a) and
[a] are monoids?

Thanks for the help!