Moreover, Haskell functions can't have side effects, which means that they can't effect any changes to the "real world", like changing files, writing to the screen, printing, sending data over the network, and so on.
Haskell is different in two ways: Values are immutable by default, and mutability must be explicitly indicated with a variable type. Mutating a mutable variable is considered a side effect, and that mutable is tracked by the type system.
Although it's not as popular as Python/Java/C++, Haskell has many benefits compared to them: Concise, high-level, practical and also very fast. An advanced system, which provides a lot of extra safety and flexibility. Concurrency is easy compared to many other languages.
The Either type is sometimes used to represent a value which is either correct or an error; by convention, the Left constructor is used to hold an error value and the Right constructor is used to hold a correct value (mnemonic: "right" also means "correct").
User-defined control structures
Haskell has no shorthand ternary operator. The built-in if
-then
-else
is always ternary, and is an expression (imperative languages tend to have ?:
=expression, if
=statement). If you want, though,
True ? x = const x
False ? _ = id
will define (?)
to be the ternary operator:
(a ? b $ c) == (if a then b else c)
You'd have to resort to macros in most other languages to define your own short-circuiting logical operators, but Haskell is a fully lazy language, so it just works.
-- prints "I'm alive! :)"
main = True ? putStrLn "I'm alive! :)" $ error "I'm dead :("
Hoogle
Hoogle is your friend. I admit, it's not part of the "core", so cabal install hoogle
Now you know how "if you're looking for a higher-order function, it's already there" (ephemient's comment). But how do you find that function? With hoogle!
$ hoogle "Num a => [a] -> a"
Prelude product :: Num a => [a] -> a
Prelude sum :: Num a => [a] -> a
$ hoogle "[Maybe a] -> [a]"
Data.Maybe catMaybes :: [Maybe a] -> [a]
$ hoogle "Monad m => [m a] -> m [a]"
Prelude sequence :: Monad m => [m a] -> m [a]
$ hoogle "[a] -> [b] -> (a -> b -> c) -> [c]"
Prelude zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
The hoogle-google programmer is not able to write his programs on paper by himself the same way he does with the help of the computer. But he and the machine together are a forced not* to be reckoned with.
Btw, if you liked hoogle be sure to check out hlint!
My brain just exploded
If you try to compile this code:
{-# LANGUAGE ExistentialQuantification #-}
data Foo = forall a. Foo a
ignorefoo f = 1 where Foo a = f
You will get this error message:
$ ghc Foo.hs Foo.hs:3:22: My brain just exploded. I can't handle pattern bindings for existentially-quantified constructors. Instead, use a case-expression, or do-notation, to unpack the constructor. In the binding group for Foo a In a pattern binding: Foo a = f In the definition of `ignorefoo': ignorefoo f = 1 where Foo a = f
Free Theorems
Phil Wadler introduced us to the notion of a free theorem and we've been abusing them in Haskell ever since.
These wonderful artifacts of Hindley-Milner-style type systems help out with equational reasoning by using parametricity to tell you about what a function will not do.
For instance, there are two laws that every instance of Functor should satisfy:
But, the free theorem tells us we need not bother proving the first one, but given the second it comes for 'free' just from the type signature!
fmap :: Functor f => (a -> b) -> f a -> f b
You need to be a bit careful with laziness, but this is partially covered in the original paper, and in Janis Voigtlaender's more recent paper on free theorems in the presence of seq
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With