Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 9258435
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 18, 20262026-06-18T12:24:11+00:00 2026-06-18T12:24:11+00:00

While hacking something up earlier, I created the following code: newtype Callback a =

  • 0

While hacking something up earlier, I created the following code:

newtype Callback a = Callback { unCallback :: a -> IO (Callback a) }

liftCallback :: (a -> IO ()) -> Callback a
liftCallback f = let cb = Callback $ \x -> (f x >> return cb) in cb

runCallback :: Callback a -> IO (a -> IO ())
runCallback cb =
    do ref <- newIORef cb
       return $ \x -> readIORef ref >>= ($ x) . unCallback >>= writeIORef ref

Callback a represents a function that handles some data and returns a new callback that should be used for the next notification. A callback which can basically replace itself, so to speak. liftCallback just lifts a normal function to my type, while runCallback uses an IORef to convert a Callback to a simple function.

The general structure of the type is:

data T m a = T (a -> m (T m a))

It looks much like this could be isomorphic to some well-known mathematical structure from category theory.

But what is it? Is it a monad or something? An applicative functor? A transformed monad? An arrow, even? Is there a search engine similar Hoogle that lets me search for general patterns like this?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-18T12:24:12+00:00Added an answer on June 18, 2026 at 12:24 pm

    The term you are looking for is free monad transformer. The best place to learn how these work is to read the “Coroutine Pipelines” article in issue 19 of The Monad Reader. Mario Blazevic gives a very lucid description of how this type works, except he calls it the “Coroutine” type.

    I wrote up his type in the transformers-free package and then it got merged into the free package, which is its new official home.

    Your Callback type is isomorphic to:

    type Callback a = forall r . FreeT ((->) a) IO r
    

    To understand free monad transformers, you need to first understand free monads, which are just abstract syntax trees. You give the free monad a functor which defines a single step in the syntax tree, and then it creates a Monad from that Functor that is basically a list of those types of steps. So if you had:

    Free ((->) a) r
    

    That would be a syntax tree that accepts zero or more as as input and then returns a value r.

    However, usually we want to embed effects or make the next step of the syntax tree dependent on some effect. To do that, we simply promote our free monad to a free monad transformer, which interleaves the base monad between syntax tree steps. In the case of your Callback type, you are interleaving IO in between each input step, so your base monad is IO:

    FreeT ((->) a) IO r
    

    The nice thing about free monads is that they are automatically monads for any functor, so we can take advantage of this to use do notation to assemble our syntax tree. For example, I can define an await command that will bind the input within the monad:

    import Control.Monad.Trans.Free
    
    await :: (Monad m) => FreeT ((->) a) m a
    await = liftF id
    

    Now I have a DSL for writing Callbacks:

    import Control.Monad
    import Control.Monad.Trans.Free
    
    printer :: (Show a) => FreeT ((->) a) IO r
    printer = forever $ do
        a <- await
        lift $ print a
    

    Notice that I never had to define the necessary Monad instance. Both FreeT f and Free f are automatically Monads for any functor f, and in this case ((->) a) is our functor, so it automatically does the right thing. That’s the magic of category theory!

    Also, we never had to define a MonadTrans instance in order to use lift. FreeT f is automatically a monad transformer, given any functor f, so it took care of that for us, too.

    Our printer is a suitable Callback, so we can feed it values just by deconstructing the free monad transformer:

    feed :: [a] -> FreeT ((->) a) IO r -> IO ()
    feed as callback = do
        x <- runFreeT callback
        case x of
            Pure _ -> return ()
            Free k -> case as of
                []   -> return ()
                b:bs -> feed bs (k b)
    

    The actual printing occurs when we bind runFreeT callback, which then gives us the next step in the syntax tree, which we feed the next element of the list.

    Let’s try it:

    >>> feed [1..5] printer
    1
    2
    3
    4
    5
    

    However, you don’t even need to write all this up yourself. As Petr pointed out, my pipes library abstracts common streaming patterns like this for you. Your callback is just:

    forall r . Consumer a IO r
    

    The way we’d define printer using pipes is:

    printer = forever $ do
        a <- await
        lift $ print a
    

    … and we can feed it a list of values like so:

    >>> runEffect $ each [1..5] >-> printer
    1
    2
    3
    4
    5
    

    I designed pipes to encompass a very large range of streaming abstractions like these in such a way that you can always use do notation to build each streaming component. pipes also comes with a wide variety of elegant solutions for things like state and error handling, and bidirectional flow of information, so if you formulate your Callback abstraction in terms of pipes, you tap into a ton of useful machinery for free.

    If you want to learn more about pipes, I recommend you read the tutorial.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

While debugging and keep pressing F5, if the source code does not exist, eclipse
while looking at some code I stumbled onto: throw /*-->*/new std::exception (//... and I
While refactoring my code base I found a piece of code which I'd like
While hacking together an authorization framework for my web app, I thought a lot
I had a problem while hacking a bigger project so I made a simpel
After hacking about for a little while on a prototype I've ended up with
While doing some hacking on my own site I encountered (after some googling) a
Is it possible to only let a user log in while using a specific
I'm hacking around on stuff that requires RSA encryption and I've got some code
While trying to build the mysql2 gem with ruby 1.9.2-p320 on Fedora 16, I

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.