21

I read in learn you haskell that

Enum members are sequentially ordered types ... Types in this class: (), Bool, Char ...

Also it appears in some signatures:

putChar  ::    Char -> IO ()

It is very difficult to find info about it in Google as the answers refer to problems of the "common parentheses" (use in function calls, precedence problems and the like).

Therefore, what does the expression () means? Is it a type? What are variables of type ()? What is used for and when is it needed?

Chilledrat
  • 2,593
  • 3
  • 28
  • 38
cibercitizen1
  • 20,944
  • 16
  • 72
  • 95
  • 2
    In general, to answer the question "is `X` a type", type `:k X` into ghci, to try to determine its kind. If `X` is a type, you'll get something like `X :: *`, read as "`X` is of kind _type_". Otherwise an error will be raised. – phipsgabler Dec 04 '13 at 18:57

4 Answers4

30

It is both a type and a value. () is a special type "pronounced" unit, and it has one value: (), also pronounced unit. It is essentially the same as the type void in Java or C/C++. If you're familiar with Python, think of it as the NoneType which has the singleton None.

It is useful when you want to denote an action that doesn't return anything. It is most commonly used in the context of Monads, such as the IO monad. For example, if you had the following function:

getVal :: IO Int
getVal = do
    putStrLn "Enter an integer value:"
    n <- getLine
    return $ read n

And for some reason you decided that you just wanted to annoy the user and throw away the number they just passed in:

getValAnnoy :: IO ()
getValAnnoy = do
    _ <- getVal
    return ()  -- Returns nothing

However, return is just a Monad function, so we could abstract this a bit further

throwAwayResult :: Monad m => m a -> m ()
throwAwayResult action = do
    _ <- action
    return ()

Then

getValAnnoy = throwAwayResult getVal

However, you don't have to write this function yourself, it already exists in Control.Monad as the function void that is even less constraining and works on Functors:

void :: Functor f => f a -> f ()
void fa = fmap (const ()) fa

Why does it work on Functor instead of Monad? Well, for each Monad instance, you can write the Functor instance as

instance Monad m => Functor m where
    fmap f m = m >>= return . f

But you can't make a Monad out of every Functor. It's like how a square is a rectangle but a rectangle isn't always a square, Monads form a subset of Functors.

bheklilr
  • 53,530
  • 6
  • 107
  • 163
  • Thanks. And then, what does it means `IO ()`? – cibercitizen1 Dec 04 '13 at 16:23
  • 1
    It means monad `IO`, that can contain only one thing — `()` of type `()`. – andrybak Dec 04 '13 at 16:24
  • 1
    @cibercitizen1 `IO` is a type constructor, it takes a type and gives another (like `[]`, which takes any type and "makes" lists of that). `IO ()` is the `IO` type constructor applied to (), to indicate, sort of, that `putChar` does not return a monadic value (since it always returns the same..). – Guido Dec 04 '13 at 16:27
  • 2
    @cibercitizen1 See my edits, they should hopefully explain it – bheklilr Dec 04 '13 at 16:28
  • @bheklilr I thought `void` type in C++ and Java doesn't have any values. – andrybak Dec 04 '13 at 16:30
  • @AndreyRybak I didn't say that `void` in C++ or Java had a value, I said that it was essentially the same concept. The `void` value represents no return value from a function, while in Haskell everything _must_ have a return value, even if that value is `()`. – bheklilr Dec 04 '13 at 16:37
  • @bheklilr even though it's used to represent the same concept, [the slight difference](http://en.wikipedia.org/wiki/Unit_type#Void_type_as_unit_type) should be understood. – andrybak Dec 04 '13 at 16:45
  • @AndreyRybak I agree that the difference is important to understand, but for someone just learning Haskell they don't need to jump into the subtle difference between its type system and that of C/C++/Java. – bheklilr Dec 04 '13 at 16:50
  • 2
    One way to reconcile the imperative programming concept of `void` with Haskell's `()` is the following: `void` is the type of *empty records*, records with no fields. Since there are no fields, any two empty records are trivially equal, just by virtue of being empty. Since it has no fields, you can store an empty record as a block of 0 bytes. The only typesafe operations on an empty record are those that don't read any data from it—because there is no data to be read! – Luis Casillas Dec 04 '13 at 17:23
  • @LuisCasillas `void` isn't really the type of empty records is it? You can't return an empty record from `void foo (void)`. – J. Abrahamson Dec 04 '13 at 17:46
  • @J.Abrahamson Oh, duh, I meant that as an analogy, and I said it as a statement. But basically there is some sort of isomorphism between the concepts of "the function returns with no result value" and "the function returns an empty record". – Luis Casillas Dec 04 '13 at 17:58
  • @J.Abrahamson Personally, I view that as a wart, not as something fundamental. For example, I think it's merely inconsistent, rather than important, that in C I can write `int foo(); int bar() { return foo(); }` but not `void foo(); void bar() { return foo(); }`. – Daniel Wagner Dec 04 '13 at 18:33
  • @LuisCasillas I actually did interpret it metaphorically, but I'm not familiar with reasoning about imperative languages in the same way I do with Haskell so I'm trying on some ideas for size. In Haskell I'd say we have `fmap absurd :: f Void -> f ()` but there's something really significantlly different about `[()]` and `[Void]`. But in C we don't have the same level of control over effects so maybe `CIO () -> CIO Void`, too. – J. Abrahamson Dec 04 '13 at 19:00
  • @DanielWagner I'd agree with that, but `foo()` still isn't an empty record. I'm beginning to see that the point doesn't matter after thinking about @LuisCasillas's idea of having `CIO () -> CIO Void`. – J. Abrahamson Dec 04 '13 at 19:03
  • @J.Abrahamson Possibly the key thing here is that imperative languages have strict semantics, so `return undefined >>= f == f undefined == undefined`. So a `CIO Void` action can never deliver a value to the function we bind it to. Note also that in Haskell implementations we need to pass thunks of type `()` around because of laziness—we don't know if a given thunk is `()` or bottom unless we force it. In a strict language, on the other hand, we only pass around things that we know aren't bottom, so `()` can be represented as *no data at all*. – Luis Casillas Dec 04 '13 at 20:17
9

As others have said, it's the unit type which has one value called unit. In Haskell syntax this is easily, if confusingly, expressed as () :: (). We can make our own quite easily as well.

data Unit = Unit

>>> :t Unit :: Unit
Unit :: Unit
>>> :t () :: ()
() :: ()

It's written as () because it behaves very much like an "empty tuple" would. There are theoretical reasons why this holds, but honestly it makes a lot of simple intuitive sense too.

It's often used as the argument to a type constructor like IO or ST when its the context of the value that's interesting, not the value itself. This is intuitively true because if I tell you have I have a value of type () then you don't need to know anything more---there's only one of them!

putStrLn :: String -> IO ()     -- the return type is unimportant,
                                -- we just want the *effect*

map (const ()) :: [a] -> [()]   -- this destroys all information about a list
                                -- keeping only the *length*

>>> [ (), (), () ] :: [()]      -- this might as well just be the number `3`
                                -- there is nothing else interesting about it

forward :: [()] -> Int          -- we have a pair of isomorphisms even
forward = length

backward :: Int -> [()]
backward n = replicate n ()
J. Abrahamson
  • 72,246
  • 9
  • 135
  • 180
6

It is both a type and a value.

It is unit type, the type that has only one value. In Haskell its name and only value looks like empty tuple : ().

andrybak
  • 2,129
  • 2
  • 20
  • 40
4

As others have said, () in Haskell is both the name of the "unit" type, and the only value of said type.

One of the confusing things in moving from imperative programming to Haskell is that the way the languages deal with the concept of "nothing" is different. What's more confusing is the vocabulary, because imperative languages and Haskell use the term "void" to mean diametrically different things.

In an imperative language, a "function" (which may not be a true mathematical function) may have "void" as its return type, as in this pseudocode example:

void sayHello() {
    printLn("Hello!");
}

In this case, void means that the "function," if it returns, will not produce a result value. (The other possibility is that they function may not return—it may loop forever, or fail with an error or exception.)

In Haskell, however, all functions (and IO actions) must must produce a result. So when we write an IO action that doesn't produce any interesting return value, we make it return ():

sayHello :: IO ()
sayHello = putStrLn "Hello!"

Later actions will just ignore the () result value.

Now, you probably don't need to worry too much about this, but there is one place where this gets confusing, which is that in Haskell there is a type called Void, but it means something completely different from the imperative programming void. Because of this, the word "void" becomes a minefield when comparing Haskell and imperative languages, because the meaning is completely different when you switch paradigms.

In Haskell, Void is a type that doesn't have any values. The largest consequence of this is that in Haskell a function with return type Void can never return, it can only fail with an error or loop forever. Why? Because the function would have produce a value of type Void in order to return, but there isn't such a value.

This is however not relevant until you're working with some more advanced techniques, so you don't need to worry about it other than to beware of the word "void."

But the bigger lesson is that the imperative and the Haskell concepts of "no return value" are different. Haskell distinguishes between:

  1. Things that may return but whose result won't have any information (the () type);
  2. Things that cannot return, no matter what (the Void type).

The imperative void corresponds to the former, and not the latter.

Luis Casillas
  • 29,802
  • 7
  • 49
  • 102
  • This confuses me. I'd say that imperative `void` still conforms to the latter notion, it's just that imperative functions are always "wrapped in `IO`". It's perfectly reasonable to write `putStrLn :: String -> IO Void`, it's just not reasonable to try to do anything with the "value". – J. Abrahamson Dec 04 '13 at 19:05
  • 1
    @J.Abrahamson: `printf` is still a function of the first type. A better example of Void in an imperative setting would be the `exit` function or an `assert` statement. – hugomg Dec 10 '13 at 03:14