Skip to content

Instantly share code, notes, and snippets.

@akiradeveloper
Created August 9, 2011 02:58
Show Gist options
  • Save akiradeveloper/1133308 to your computer and use it in GitHub Desktop.
Save akiradeveloper/1133308 to your computer and use it in GitHub Desktop.
While Functor prototype failure
newtype While a = While { get :: (a, Bool) }
instance Functor While where
fmap f (While (a, True)) = let (a', b) = f a in While (a', b)
fmap _ (While (a, False)) = While (a, False)
countDown :: Int -> (Int, Bool)
countDown i =
let i' = i - 1
in
if i' < 0 then (i, False) else (i', True)
main = do
let result = get $ While (1, True) `fmap` countDown `fmap` countDown
print result
@akiradeveloper
Copy link
Author

Thanks for your advice.
I guess promoting While functor to monad and typing countDown Int -> While (Int, Bool) will do. I will try.

@akiradeveloper
Copy link
Author

Yeah, I made it. But, it is still strange somehow. Anyway, the code can be compiled, runs and works as we expect.

newtype While a = While { get :: (a, Bool) }

instance Monad While where
  return x = While (x, True)
  -- f :: a -> While b
  While (x, True) >>= f = f x
  While (x, False) >>= f = f x

countDown :: Int -> While Int
countDown i = do
  let i' = i - 1
  if i' < 0 
    then While (i, False)
    else While (i', True)

main = do
  let result1 = get $ return 1 >>= countDown
  print result1
  let result2 = get $ return 1 >>= countDown >>= countDown >>= countDown
  print result2

@md2perpe
Copy link

md2perpe commented Aug 9, 2011

The boolean value isn't really used. This is practically just Identity monad.

BTW, you can change the implementation of coundDown to:

countDown :: Int -> While Int
countDown i = do
  let i' = i - 1
  While (i, i' >= 0)

which can be even simplified to

countDown :: Int -> While Int
countDown i = While (i, i >= 1)

Could you explain what you are trying to do?

@akiradeveloper
Copy link
Author

Thanks.
One, You are right! This is definitely Identity monad.
Two, You may be wrong. Your countDown implementations are not the same as mine because my version returns While monad with i' if the condition is True whereas with i if False. The difference is your version always returns with i.

@md2perpe
Copy link

md2perpe commented Aug 9, 2011

You're right. I didn't notice the ' after one of the i:s.

You could however write

While $ if i' < 0 
  then (i, False)
  else (i', True)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment