简体   繁体   中英

Why is the output of this Haskell function an IO String instead of a String

I'm learning Haskell through learnyouahaskell.com and wanted to test some of the concepts before finishing the input/output module. I haven't been able to google or hoogle my way out of this question, though, even though it seems quite simple.

When I try to run the following code

getName = do
  name <- getLine
  return name

the output of getName becomes an element of type IO String instead of String , even though name is definitely a String

By reading the documentation and other StackVverflow's questions I couldn't figure out why is this happening when I declare getName as a function (when I use the bind <- operation directly on main there's no problem whatsoever).

The return function is not conceptually the same as what return does in languages like C++, Java and Python. return :: Monad m => a -> ma takes an a (here a String ), and produces an ma (here IO a ).

The do notation is syntacticual sugar. If we desugar the statement, you wrote:

getName = getLine >>= (\name -> return name)

or cleaner:

getName = getLine >>= return

The bind function (>>=) :: Monad m => ma -> (a -> mb) -> mb thus has as first operand an ma , and as second a function a -> mb , and produces an mb . Since getLine :: IO String is an IO String , that thus means that m is the same as IO , and a is the same as String . The return :: Monad m => a -> ma , makes it clear that here b is the same as a .

Then what is IO here. A metaphor that is frequently used is the one of a recipe . In this metaphor an IO a is a set of instructions that when you follow these, you will get an a . But that does not mean that that recipe is an a .

(>>=) here basically says that, on the left hand I have a recipe to make a , on the right hand I have a function that converts that a into a recipe to make b , so we can construct a recipe to make b with these two.

People often ask how to unwrap an a out of an IO a , but conceptually it makes not much sense. You can not "unwrap" the cake out of a recipe to make a cake. You can follow the instructions to make a cake. Following instructions is something the main will eventually do. We thus can construct a (long) recipe the main will do. But we can not unwrap the values.

Strictly speaking there is a function unsafePerformIO :: IO a -> a that can do that. But it is strongly adviced not to use that. Functions in Haskell are supposed to be pure that means that for the same input, we always retrieve the same output. getLine itself is a pure, since it always produces the same recipe ( IO String ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM