Haskell
Cool things
- Sum-types (i.e.
|) >>=Forcieren Reihenfolge => Imperativer code (ein wenig wie der pipe|operator.=>: Linke Seite legt contraints auf einzelne rechts auftauchende Dinge fest, z.B.insert :: (Ord k) => k -> v -> BinaryTree k v -> BinaryTree k vist hierkvom typOrd.
Trick
let result :: _Compile and let haskell tell you the type of the wildcard _
Conventions
Functions
- Function name starts with lower caps
- We usually use
'to denote either a strict version of a function (i.e., one that isn’t lazy), or a slightly modified version of a function or variable with a similar name, e.g.myFunction'. minBound,maxBound
Definition/name vs. Function
No parameters
Operators
- Unequal:
/=
Functions
Equivalent prefix and infix function calls:
div 92 10and
92 `div` 10- If a function is composed of only special characters, it’s considered an infix function by default.
-
$: Calling a function, e.g.Foo $ a bApply Function application
$to List:ghci> map ($ 3) [(4+), (10*), (^2), sqrt] [7.0,30.0,9.0,1.7320508075688772] -
.: Function composition(.) :: (b -> c) -> (a -> b) -> a -> c
Function definitions
doubleMe x = x + xConditionals
Else is mandatory!
doubleSmallNumber x = if x > 100
then x
else x*2Haskell’s if is an expression that must return a value, and not a statement.
Lists
- Homogeneous data structure
- Concatenation:
++ ['h','e','l','l','o']is equivalent to the stringhello- Cons:
:(Prepend a single item to list, e.g.5 : [4,3,2,1]) - Empty list:
[] - Retrieve value by index:
"Some sentence" !! 4 head,tail,last,reverse,take,drop(from beginning),maximum,minimum,sum,product,elem(usually called as infix function)null: Check whether list is emptyzip [1,2,3,4,5] [5,5,5,5,5]creates pairs
List comprehension
Examples:
[x*2 | x <- [1..10]][ x | x <- [50..100], x `mod` 7 == 3]- Output all combinations of two lists:
[adjective ++ " " ++ noun | adjective <- adjectives, noun <- nouns] length' xs = sum [1 | _ <- xs](_because we don’t use it)removeNonUppercase st = [ c | c <- st, celem['A'..'Z']]
Ranges
[1..20],['A'..'Z'],[3,6..20]- Infinite ranges:
take 24 [13, 26..] cycle,repeat:take 10 repeat 8replicate 10 1
Tuples
- Heterogeneous data structure
- E.g. (1,3)
- For pairs:
fst,snd
Currying
functions to tuples
Types
Since Haskell is a statically typed language, it needs to know all the types before the code is compiled (or in the case of GHCi, evaluated)
Functions which use type are called polymorphic functions.
"Abrakadabra" `compare` "Zebra"—>LTShowtype.showprints value as stringEnum: Succ
Type classes: (MyTypeClass a) => a -> a -> Bool
Numvs.Integral- Type synonyms:
type Foo = String ($) :: (a -> b) -> a -> b
Functors
Functor is data type.
class Functor f where
fmap :: (a -> b) -> f a -> f b
<$> :: (a -> b) -> f a -> f b
-- Compare:
($) :: (a -> b) -> a -> b
<*> :: m (a -> b) -> m a -> m bfis a type constructor-
e.g.
instance Functor [] where fmap = maphere
[]is a type constructor which can be used as[Int]
Maybe Int is a concrete type, but Maybe is a type constructor that takes one type as the parameter.
Monad
Media about Monads
Course notes
Famous monads: Maybe, Either, IO
Because of monads error handling can be deferred to the monads and code is nicely imperative with the do-notation.
m b I can bind with <-
C komma operator ~ >> operator
-
Imperative if-else:
when :: (Monad m) => Bool => m () -> m () when condition action = if condition then action else ()()is no action likevoid. pure=return(syntactic sugar)
IO is monad, so you can create monad versions of map, replicate etc. so that user input can be used with it.
Work with monadic actions …
Monadisapplicativeandfunctor-
for loop:
for :: [a] -> (a -> m b) -> m [b] == forM mapM :: (a -> m b) -> [a] -> m [b] map :: (a -> b) -> [a] -> [b] -
Replace a chain of monad with bindings
(>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c) f >=> g = \x -> f x >>= g f >=> g = \x -> ((>>= g) . f) x f >=> g = (>>= g) . f (>>=) :: (a -> m b) -> m a -> m b f >>= x = ...>=> ... >=> ...>>= \x -> (...) x >>= \y -> (...) y -
The following three are identical:
allArticles <- fmap concat $ pooledForConcurrentlyN 4 keywords $ \keywords -> do articleList <- getArticlesByKeyword keywords return articleList allArticles <- fmap concat $ pooledForConcurrentlyN 4 keywords $ \keywords -> do getArticlesByKeyword keywords allArticles <- concat <$> pooledMapConcurrentlyN 4 getArticlesByKeyword keywords
Applicative
—> Auswerte Reihenfolge
join -> (better name: flatten)
>>= ~ flatMap , wird oft bind genannt (kommt im Haskell logo vor).
“apply” (TODO: Compare with Javascript)
Types:
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f aMonad
-
<--- If `foo` is of type IO, `bar` is unpacked `foo`, thus not of type IO bar <- foo
Comments
-- or {- ... -}
Modules
module Module1 (x, square) where
...module ProjectX.Module2 where
...import Module1 (square, x)
import ProejctX.Module2 (SomeTypeimport Foo hiding (myMap): Import all butmyMap- In many packages
.internal
Records & Accessors
IO
“IO Unit” IO ()
print = puStrLn . showis equivalent toprint x = putStrLn (show x)
Useful to know
flip: flips arguments of function- inside
do ...you have to define new variables with let <>is generalization of++concatenationT.pack someStringwird zu type Text.-
.: Apply functions in row:foo = doFirst . doSecond -- Equivalent: foo a = doFirst (doSecond a) _ -> ...handle all other cases which are not pattern matched.
Similarity to javascript/python
Be aware that reduce is actually a foldl, in Haskell terms. There is no special syntax to perform folds, there’s no builtin foldr, and actually using reduce with non-associative operators is considered bad style. Source
Links
Discuss on Twitter ● Improve this article: Edit on GitHub