Skip to content

Instantly share code, notes, and snippets.

@fronx
Last active August 29, 2015 14:06
Show Gist options
  • Save fronx/551f91b4e3d0a33f0c26 to your computer and use it in GitHub Desktop.
Save fronx/551f91b4e3d0a33f0c26 to your computer and use it in GitHub Desktop.
fmap allows you to use a function in a computational context it doesn't know anything about
{-# LANGUAGE ScopedTypeVariables #-}
module InputNumber where
import Text.Read
-- let's make fmap look more like a wire
(<~) :: Functor f => (a -> b) -> f a -> f b
(<~) = fmap
-- this one allows us to feed values from left to right
(~>) :: Functor f => f a -> (a -> b) -> f b
(~>) = flip (<~)
readInt :: String -> Maybe Int
readInt = readMaybe
-- retry models an IO operation with parsing and retries
--
-- given a parse function that can fail (a -> Maybe b) and
-- an IO operation `src` that produces values of type `a`,
-- retry reading from `src` and parsing until it succeeds
retry :: forall a b. (a -> Maybe b) -> IO a -> IO b
retry parse src = -- progression of types
-- for clarity
(((( src :: IO a)
-- here we are using the left-to-right |
-- wire to feed `a`s that are inside | via fmap
-- of IO into a function that doesn't |
-- know anything about IO V
~> parse) :: IO (Maybe b))
>>= maybe (retry parse src) return) :: IO b
main = do
print =<< retry readInt getLine
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment