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

  • SEARCH
  • Home
  • 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 6378629
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 25, 20262026-05-25T02:01:57+00:00 2026-05-25T02:01:57+00:00

I was playing around with composable failures and managed to write a function with

  • 0

I was playing around with composable failures and managed to write a function with the signature

getPerson :: IO (Maybe Person)

where a Person is:

data Person = Person String Int deriving Show

It works and I’ve written it in the do-notation as follows:

import Control.Applicative

getPerson = do
    name <- getLine -- step 1
    age  <- getInt  -- step 2
    return $ Just Person <*> Just name <*> age 

where

getInt :: IO (Maybe Int)
getInt = do
    n <- fmap reads getLine :: IO [(Int,String)]
    case n of
        ((x,""):[])   -> return (Just x)
        _ -> return Nothing

I wrote this function with the intent of creating composable possible failures. Although I’ve little experience with monads other than Maybe and IO this seems like if I had a more complicated data type with many more fields, chaining computations wouldn’t be complicated.

My question is how would I rewrite this without do-notation? Since I can’t bind values to names like name or age I’m not really sure where to start.

The reason for asking is simply to improve my understanding of (>>=) and (<*>) and composing failures and successes (not to riddle my code with illegible one-liners).

Edit: I think I should clarify, “how should I rewrite getPerson without do-notation”, I don’t care about the getInt function half as much.

  • 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-05-25T02:01:58+00:00Added an answer on May 25, 2026 at 2:01 am

    Do-notation desugars to (>>=) syntax in this manner:

    getPerson = do
        name <- getLine -- step 1
        age  <- getInt  -- step 2
        return $ Just Person <*> Just name <*> age
    
    getPerson2 =
      getLine >>=
       ( \name -> getInt >>=
       ( \age  -> return $ Just Person <*> Just name <*> age ))
    

    each line in do-notation, after the first, is translated into a lambda which is then bound to the previous line. It’s a completely mechanical process to bind values to names. I don’t see how using do-notation or not would affect composability at all; it’s strictly a matter of syntax.

    Your other function is similar:

    getInt :: IO (Maybe Int)
    getInt = do
        n <- fmap reads getLine :: IO [(Int,String)]
        case n of
            ((x,""):[])   -> return (Just x)
            _ -> return Nothing
    
    getInt2 :: IO (Maybe Int)
    getInt2 =
        (fmap reads getLine :: IO [(Int,String)]) >>=
         \n -> case n of
            ((x,""):[])   -> return (Just x)
            _             -> return Nothing
    

    A few pointers for the direction you seem to be headed:

    When using Control.Applicative, it’s often useful to use <$> to lift pure functions into the monad. There’s a good opportunity for this in the last line:

    Just Person <*> Just name <*> age
    

    becomes

    Person <$> Just name <*> age
    

    Also, you should look into monad transformers. The mtl package is most widespread because it comes with the Haskell Platform, but there are other options. Monad transformers allow you to create a new monad with combined behavior of the underlying monads. In this case, you’re using functions with the type IO (Maybe a). The mtl (actually a base library, transformers) defines

    newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
    

    This is the same as the type you’re using, with the m variable instantiated at IO. This means you can write:

    getPerson3 :: MaybeT IO Person
    getPerson3 = Person <$> lift getLine <*> getInt3
    
    getInt3 :: MaybeT IO Int
    getInt3 = MaybeT $ do
        n <- fmap reads getLine :: IO [(Int,String)]
        case n of
            ((x,""):[])   -> return (Just x)
            _             -> return Nothing
    

    getInt3 is exactly the same except for the MaybeT constructor. Basically, any time you have an m (Maybe a) you can wrap it in MaybeT to create a MaybeT m a. This gains simpler composability, as you can see by the new definition of getPerson3. That function doesn’t worry about failure at all because it’s all handled by the MaybeT plumbing. The one remaining piece is getLine, which is just an IO String. This is lifted into the MaybeT monad by the function lift.

    Edit
    newacct’s comment suggests that I should provide a pattern matching example as well; it’s basically the same with one important exception. Consider this example (the list monad is the monad we’re interested in, Maybe is just there for pattern matching):

    f :: Num b => [Maybe b] -> [b]
    f x = do
      Just n <- x
      [n+1]
    
    -- first attempt at desugaring f
    g :: Num b => [Maybe b] -> [b]
    g x = x >>= \(Just n) -> [n+1]
    

    Here g does exactly the same thing as f, but what if the pattern match fails?

    Prelude> f [Nothing]
    []
    
    Prelude> g [Nothing]
    *** Exception: <interactive>:1:17-34: Non-exhaustive patterns in lambda
    

    What’s going on? This particular case is the reason for one of the biggest warts (IMO) in Haskell, the Monad class’s fail method. In do-notation, when a pattern match fails fail is called. An actual translation would be closer to:

    g' :: Num b => [Maybe b] -> [b]
    g' x = x >>= \x' -> case x' of
                          Just n -> [n+1]
                          _      -> fail "pattern match exception"
    

    now we have

    Prelude> g' [Nothing]
    []
    

    fails usefulness depends on the monad. For lists, it’s incredibly useful, basically making pattern matching work in list comprehensions. It’s also very good in the Maybe monad, since a pattern match error would lead to a failed computation, which is exactly when Maybe should be Nothing. For IO, perhaps not so much, as it simply throws a user error exception via error.

    That’s the full story.

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

Sidebar

Related Questions

After playing around with haskell a bit I stumbled over this function: Prelude Data.Maclaurin>
After playing around with links in Rails for a view hours i've managed to
I'm playing around with an idea(never played with TypeDescriptors before), and managed to get
After playing around with URL decoding myself, I managed to come up with some
Playing around in Mono 2.10 REPL: csharp> string a = true; csharp> a.ToBoolean(CultureInfo.InvariantCulture); {interactive}(1,4):
I playing around with a function that I want to bind to all the
Playing around with Python - tkInter - Entry widget - when I use validatecommand
Playing around with MongoDB and NoRM in .NET. Thing that confused me - there
Just playing around with the now released Silverlight 2.0. I'm trying to put a
While playing around with regexps in Scala I wrote something like this: scala> val

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.