Below, I have collected several examples of "uncanny" Haskell. These are things that may be surprising to those who have learned the language merely by doing.

IO Type

The IO type is in fact not primitive to Haskell and is defined as follows:

newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))

While this is not exactly uncanny (it is deep and well-engineered), it is likely unfamiliar to many; we can in fact pattern match our way out of IO.

Empty where Clauses

The following is valid:

x :: Int x = 3 where

Empty let Declarations

The following is valid:

x :: Int x = let in 3

Empty data Declarations

The following is from ghc-prim:

data RealWorld

This has real-world use, much like the definition for IO.

Functorial Template Haskell

As template Haskell at the top level is a Haskell value of type Q [Dec], we can do the following:

fold <$> traverse makeLenses [''Type, ''SomeOtherType, ''YetAnotherType]


otherwise is defined in Data.Bool as

otherwise :: Bool otherwise = True

Thus it makes for clearer guards, but it could in principle be overloaded or misused, viz.

subsets = filterM (pure [otherwise, False])

Function-Level Recursion

Function-level recursion is possible (and even desirable!) in Haskell. The classic example is recursion schemes; below is a hylomorphism.

hylo :: Functor f => (f b -> b) -> (a -> f a) -> a -> b hylo f g = h where h = f . fmap h . g

Void Semigroup

The Void type is much like the RealWorld type; it has no constructors.

data Void

We can define a Semigroup instance for it, viz.

instance Semigroup Void where a <> _ = a

We can also use another bit of uncanny Haskell to define absurd: an empty case statement.

absurd :: Void -> a absurd a = case a of {}


Haskell accepts any value in the IO monad as main, and in fact you can write

main :: IO Int main = pure 4

Rearranged Definitions

Haskell allows type signatures to be placed anywhere in the file. Thus one could write:

plusOne :: Int -> Int timesTwo :: Int -> Int timesTwo = (*2) plusOne = (+1)