What does '@' mean in Haskell?
It is used in pattern matching. Now node
variable will refer to the entire Node
data type for the argument Node a b c l r
. So instead of passing to the function as Node a b c l r
, you can use node
instead to pass it up.
A much simpler example to demonstrate it:
data SomeType = Leaf Int Int Int | Nil deriving Show
someFunction :: SomeType -> SomeType
someFunction leaf@(Leaf _ _ _) = leaf
someFunction Nil = Leaf 0 0 0
The someFunction
can also be written as:
someFunction :: SomeType -> SomeType
someFunction (Leaf x y z) = Leaf x y z
someFunction Nil = Leaf 0 0 0
See how simpler was the first version ?
Using @t as a type indicator
Besides the argument pattern matching usage described in the answer of @Sibi, in Haskell the "at" character ('@', also known as an arobase character) can be used in some contexts to force a typing decision. This is mentioned in the comments by @Josh.F.
This is not part of the default language features, and is known as the Type Application Haskell language extension. In summary, the extension allows you to give explicit type arguments to a polymorphic function such as read
. In a classic .hs source file, the relevant pragma must be included:
{-# LANGUAGE TypeApplications #-}
Example:
$ ghci
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
λ>
λ> let x = (read @Integer "33")
<interactive>:4:10: error:
Pattern syntax in expression context: read@Integer
Did you mean to enable TypeApplications?
λ>
λ> :set -XTypeApplications
λ>
λ> let x = (read @Integer "33")
λ>
λ> :type x
x :: Integer
λ>
λ> x
33
λ>
Further details
For the read
polymorphic function, the type indicator introduced by @
relates to the type of the result returned by read
. But this is not generally true.
Generally speaking, you have to consider the type variables that appear in the type signature of the function at hand. For example, let's have a look at the fmap
library function.
fmap :: Functor ft => (a -> b) -> ft a -> ft b
So here, we have 3 type variables, in order of appearance: ft, a, b. If we specialize fmap
like this:
myFmap = fmap @type1 @type2 @type3
then type1
will relate to ft
, type2
will relate to a
and type3
will relate to b
. Also, there is a special dummy type indicator @_
which means: “here, any type goes”.
For example, we can force the output type of fmap
to be Integer
and the functor to be the plain list []
, leaving the input type a
unspecified:
λ>
λ> myFmap = fmap @[] @_ @Integer
λ>
λ> :type myFmap
myFmap :: (_ -> Integer) -> [_] -> [Integer]
λ>
As for the read
function, its type is:
read :: Read a => String -> a
So there is only room for one type indicator, and it relates to the type of the result returned by read
, as displayed above.