user3242611
user3242611

Reputation: 11

Trouble making simple function in haskell

I am having trouble trying to convert the following block of C code into Haskell.

void echo(int num){
  if(num != 0) 
     print(num)
  else
     exit()
}

I just started learning Haskell, but I am pretty confused as to how such a simple function could be so difficult.

Upvotes: 0

Views: 104

Answers (1)

bheklilr
bheklilr

Reputation: 54078

What makes it seem difficult in Haskell is that the type system forces you to separate these kinds of functions from those that do not alter the state of the machine, such as printing to the screen or exiting the program. In order to write a function like this you have to use the IO monad:

import System.Exit   -- Need this for exitSuccess

--                v   The () is like void
echo :: Int -> IO ()
echo n =
    if n /= 0
        then print n
        else exitSuccess

As you can see, there's nothing inherently more complex about this definition in Haskell than in the C-style languages. You just have to import the module that contains the function used to exit, and you have to write your function to work in the IO monad. You can use this function in a program as

loop :: IO ()
loop = do
    putStr "Enter a number: "
    numStr <- getLine
    echo (read numStr)
    loop

main :: IO ()
main = loop

This short snippet of code will continuously prompt the user for a number, then echo it back unless they enter 0.


I mentioned at the beginning of this answer that the type system doesn't let you mix state altering code with non-state altering code. How does it do this? In this case, any function with a type signature that ends with IO a (where a can be anything) executes in the IO monad, and only in that monad context. So you can't do something like

doubler :: Int -> Int
double n = 2 * (echo n)

This won't type check! 2 * expects the next argument to be an Int, whereas echo n has the type IO (). Even if it had the type IO Int, this is not the same as or compatible with the type Int. If instead you had

doubler :: Int -> IO Int
doubler n = do
    echo n
    return (2 * n)

You could then use it as

loop :: IO ()
loop = do
    putStr "Enter a number: "
    numStr <- getLine
    nDoubled <- doubler (read numStr)
    putStr "Your number doubled is "
    print nDoubled
    loop

Obviously, this will echo the original number, or exit the program if it's 0, then print Your number doubled is <n> where <n> is the new number, and then repeat this process until a 0 is entered.

Upvotes: 10

Related Questions