Marvin Pollock
Marvin Pollock

Reputation: 58

Haskell - Translating from syntactic sugar

the task ist to translate this

f = do
    c <- [1 .. 200]
    b <- [1 .. 200]
    guard (c >= b)
    a <- [1 .. 200]
    guard (a >= b && (c^2 - a^2 == b^2))
    return (a,b, c)

into a non-sugar verion.

I think I got most of it figured out, but I'm stuck in the middle with a problem I need to fix before I can continue. So far I have:

f = [1 .. 200] >>= \c ->
    [1 .. 200] >>= \b ->
    if (c >= b) 
        then [1 .. 200] >>= \a -> if (a >= b && (c^2 - a^2 == b^2)) 
                                      then return(a,b,c)
                                      else return ()
        else return ()

which does not compile. When I put in (a,b,c) for the return, it compiles, but obviously it does not give the expected result anymore. How do I return "nothing" in the else branches?

If I put in ((),(),()) as the return values, the compiler gets a "No instance for (Num [a]) arising from the literal '1'"

Upvotes: 1

Views: 349

Answers (2)

Daniel Fischer
Daniel Fischer

Reputation: 183978

Instead of return (), which is [()], you must produce an empty list, so else [] or, with the generic guard implementation else mzero.

The success branch produces a list of triples, [(Int,Int,Int)] (or Integer, or another Num type), so the failure branches must produce the same. Since failure means that no triple is found, they shall produce an empty list.

Note that in the [] monad, return x is just [x] and mzero (from MonadPlus) is the same as fail whatever, namely [].

Upvotes: 8

zch
zch

Reputation: 15278

guard is not actually syntactic sugar. It's a function from Control.Monad.

guard :: MonadPlus m => Bool -> m ()
guard True  = return ()
guard False = mzero

In case of lists mzero is []. Read more here: http://en.wikibooks.org/wiki/Haskell/MonadPlus

Upvotes: 5

Related Questions