Type of return in do block

后端 未结 3 1480
谎友^
谎友^ 2021-01-21 04:17

I am trying to understand Monads in Haskell and during my countless experiments with code I have encountered this thing:

f2 = do   
  return \"da\"
相关标签:
3条回答
  • 2021-01-21 04:57

    First let's just point out that

    do
      return a
    

    Is exactly the same as

    return a
    

    Now, the problem is that return has the type

    return :: Monad m => a -> m a
    

    And when you have a declaration like

    foo = bar
    

    where foo has no arguments haskell makes it "monomorphic". The result of this is that Haskell can't guess what m is and won't generalize it so you need an explicit type signature. The most general one is

    f2 :: Monad m => m String
    f2 = return "das"
    

    But you could also use IO or any other monad

    f2 :: IO String
    

    Finally, in your last example, since you're returning 2, you'd have to give a type signature that indicates you're returning some sort of number, like

     f2 :: IO Integer
    
    0 讨论(0)
  • 2021-01-21 04:59

    This is known Monomorphism_restriction

    Use signatures

    f2 :: Monad m => m String
    f2 = do   
      return "da"
    

    or use language extension:

    {-# LANGUAGE NoMonomorphismRestriction #-}
    f2 = do   
      return "da"
    

    to get valid code

    0 讨论(0)
  • 2021-01-21 05:06

    When learning about monads it's helpful to expand them out manually yourself, for instance the simple example:

    test0 :: IO String
    test0 = do
      a <- getLine
      putStrLn a
      return a
    

    If we enable the language extension {-# LANGUAGE ScopedTypeVariables #-} then we can annotate each of the lines in the monad with it's explicit type which will show the type of the return block.

    {-# LANGUAGE ScopedTypeVariables #-}
    
    test1 :: IO String
    test1 = do
      a <- getLine             :: IO String
      putStrLn a               :: IO ()
      return a                 :: IO String
    

    We can also annotate the explicit type of the left hand side pattern matching which "extracts" from the monad context on the right hand side.

    test2 :: IO String
    test2 = do
      (a :: String) <- getLine  :: IO String
      (() :: ()) <- putStrLn a  :: IO ()
      return a                  :: IO String
    

    We can even expand out the do-notation into its constituting parts:

    test3 :: IO String
    test3 = getLine >>=
            (\a -> putStrLn a >>=
            \() -> return a)
    

    Hope that helps build your monad intuition.

    0 讨论(0)
提交回复
热议问题