To try out Pipes, I decided to write an over-engineered solution to the 
FizzBuzz 
"problem"<http://imranontech.com/2007/01/24/using-fizzbuzz-to-find-developers-who-grok-coding/>
.

For the way I solved it, I needed a way to check if a 'Producer' is empty 
and conditionally pass on it's output or else run another 'Producer'. This 
is very similar to 
'ifte'<http://hackage.haskell.org/package/logict-0.6.0.1/docs/src/Control-Monad-Logic-Class.html#ifte>
 from 
the logict package. So I wrote 'ifte' for pipes:


module PipesBuzz where

import Control.Monad
import Pipes
import Pipes.Internal

-- |Logical condictional, \"if-then-else\". If the first argument sends any
--  values downstream, these values will be fed into the success branch. 
--  Otherwise the failure branch is taken.
--  
--  @
--  'ifte' :: 'Monad' m => 'Producer'   a m r -> (a -> 'Effect'       m ()) 
-> 'Effect'       m r -> 'Effect'       m r
--  'ifte' :: 'Monad' m => 'Producer'   a m r -> (a -> 'Producer'   b m ()) 
-> 'Producer'   b m r -> 'Producer'   b m r
--  'ifte' :: 'Monad' m => 'Pipe'     a b m r -> (b -> 'Consumer' a   m ()) 
-> 'Consumer' a   m r -> 'Consumer' a   m r
--  'ifte' :: 'Monad' m => 'Pipe'     a b m r -> (b -> 'Pipe'     a c m ()) 
-> 'Pipe'     a c m r -> 'Pipe'     a c m r
--  @
--
ifte :: (Monad m)
    => Proxy a' a b' b m r
    -- ^ condition
    -> (b -> Proxy a' a c' c m b')
    -- ^ \"then\"-branch
    -> Proxy a' a c' c m r
    -- ^ \"else\"-branch
    -> Proxy a' a c' c m r
ifte p0 th el = go p0
  where
    go p = case p of
        Request x' fx  -> Request x' (\x -> go (fx x))
        -- at least one value sent upstream: run THEN branch 
        Respond b  fb' -> for (Respond b fb') th
        M          m   -> M (m >>= \p' -> return (go p'))
        -- no value sent upstream: run ELSE branch
        Pure _a        -> el


And here is my FizzBuzz solution using 'ifte'. The interesting part is the 
'fizzify' function:


fizzTest :: (Monad m) => Integer -> String -> Integer -> Producer String m 
()
fizzTest d s n = when (n `mod` d == 0) (yield s)

fizz, buzz :: (Monad m) => Integer -> Producer String m ()
fizz = fizzTest 3 "Fizz"
buzz = fizzTest 5 "Buzz"

fizzify :: (Monad m) => Integer -> Producer String m ()
fizzify n = do
    ifte (mapM_ ($n) [fizz, buzz]) yield (yield (show n))
    yield "\n"

fizzBuzz :: (Monad m) => Producer String m ()
fizzBuzz = for (each [1..100]) fizzify

main :: IO ()
main = runEffect $ for fizzBuzz (lift . putStr)


I would be interested in your thoughts regarding my use of pipes. 
Especially whether you think 'ifte' is a reasonable addition to pipes or 
that some other construct should be used instead.

Cheers,
Falko

-- 
You received this message because you are subscribed to the Google Groups 
"Haskell Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].

Reply via email to