diff --git a/src/11-more-functions.md b/src/11-more-functions.md index e5b203c3351c85dd6e54252dd3e174c2c33d2c77..abb1c23a080fac50816189e4dc2e0f5212933772 100644 --- a/src/11-more-functions.md +++ b/src/11-more-functions.md @@ -78,7 +78,11 @@ Only usable in patterns, i.e. on *left-hand side* of the `=`! You can use backticks \` to write functions between their arguments. -## Example: QuickSort +```haskell +(+3) `map` [1,2,3] +``` + +## Exercise: QuickSort Sort a `[Int]` using QuickSort! diff --git a/src/12-typeclasses.md b/src/12-typeclasses.md index 62f6d906c422cf2b12ce1b8b5864807524e22401..fb1297f6f1587ee481e959227554cb1adc1a9cf7 100644 --- a/src/12-typeclasses.md +++ b/src/12-typeclasses.md @@ -8,13 +8,61 @@ Comparable to *interfaces* in object-oriented programming or *traits* in Rust. C More concrete: Typeclasses ensure that types of that typeclass have certain functions available. -## Example +## Using a typeclass + +Let's try `:t (==)`: + +```haskell +(==) :: Eq a => a -> a -> Bool +``` + +That means: `==` works for every type `a` with the typeclass `Eq`. Let's have a look at Eq: `:i Eq` + +## Writing a typeclass + +Let's extend `double` into a typeclass. + +```haskell +class Doubleable a where + double :: a -> a + +instance Doubleable Int where + double x = x * 2 + + +six = double 3 +``` + +## Caution with polymorphic types + +``` +{- Won't work! +instance Doubleable String where + double str = str ++ str +-} +``` + +`String` is a synonym for `[Char]`. Lists are a polymorphic type (`[a]`). In class instances, instantiated type variables are not allowed! ```haskell -class Ratable a where - rate :: a -> String +-- Instead: +instance Doubleable [a] where + double list = list ++ list +``` + +## Interesting pre-defined typeclasses + +`Eq`, `Ord`, `Read`, `Show`, `Enum`, `Bounded`, `Num` + +## Exercise + +Implement a typeclass for things that can be given a true or false with a function `boolify` and instanciate it for a few types. + +Example: -instance Ratable Int where - rate 42 = "Great" - rate _ = "Not so great" ``` +boolify 0 ~> False +boolify 1 ~> True +boolify [] ~> False +boolify [1,2,3,4] ~> True +``` \ No newline at end of file diff --git a/src/13-functors.md b/src/13-functors.md new file mode 100644 index 0000000000000000000000000000000000000000..8fb5bdbe3966e792303ea026e54ec98f1739fa3d --- /dev/null +++ b/src/13-functors.md @@ -0,0 +1,45 @@ +# Functors + +## What is a functor? + +Remember map? + +```haskell +map :: (a -> b) -> [a] -> [b] + +map (+3) [1,2,3] +``` + +Do something for every element of a list. + +## Not only lists + +This principle should work for more than lists! + +We can use a typeclass to let more things be mapped over. + +```haskell +class Functor f where + fmap :: (a -> b) -> f a -> f b +``` + +There is also `<$>` as short infix variant + +## Still works with lists + +```haskell +x = (+3) `fmap` [1,2,3] +y = (*2) <$> [10,4,2] +z = (==2) <$> [1,2,3] +a = (==2) <$> (*2) <$> [1,2,3] +``` + +## What else? + +`:i Functor` + +→ `Maybe`, `(,) a`, `(->) r` + + +**Exercise:** Try around with mapping on `Maybe` and lists. Implement `Functor` for `List`, our own list type. + diff --git a/src/14-monads.md b/src/14-monads.md new file mode 100644 index 0000000000000000000000000000000000000000..7043583da00b1db338939220a7ceaf29405519d9 --- /dev/null +++ b/src/14-monads.md @@ -0,0 +1,65 @@ +# Monads + +## Burrito + +A monad is like a burrito. Any questions left? + +## Starting off with functors + +- A functor is a *container* +- We can apply functions on the content of the container +- Hence `fmap :: (a -> b) -> f a -> f b`: we take a container containing `a`'s, apply a function `a -> b`, and get a container containing `b`'s + +## Monads + +- A monad is always also a functor, but with more features +- Therefore: monads are also containers +- A monad `m` has two additional features: + - `return :: a -> m a`: Wraps a bare element in the monad container. + - `(>>=) : m a -> (a -> m b) -> m b` (*"bind"*): Applies a monad function `(a -> m b)` on a monad. +- We can map functions `a -> b` over functors, each element is transformed into another element +- But on monads we can use functions `a -> (m b)`, each returning a whole container by itself! + +## Trying it out on lists + +Monadic functions `a -> m b` can be chained together + +```haskell +x = list >>= \x -> [-x,x] >>= \x -> [x + 1, x + 2] +``` + +## do-notation + +```haskell +dolist :: [Int] +dolist = do + a <- list + b <- [-a, a] + [b+1, b+2] +``` + + +## Understanding IO a little better + +`[a]` are monads: A container containing `a`s as alements you can get out with `>>=`. +`IO a` are monads: A container with a *state* containing `a`s as *result* you can get out with `>>=` + +```haskell +main :: IO () +main = do + putStrLn "What is your name?" + name <- getLine + putStrLn ("Hello " ++ name ++ "!") +``` + +```haskell +putStrLn :: String -> IO () +getLine :: IO String +``` + +```haskell +main :: IO () +main = putStrLn "What is your name?" + >>= \_ -> getLine + >>= \name -> putStrLn ("Hello " ++ name ++ "!") +``` \ No newline at end of file diff --git a/src/15-project-management.md b/src/15-project-management.md new file mode 100644 index 0000000000000000000000000000000000000000..83cb1a5d89aaf3da1588ed43e4b41d92d36a4561 --- /dev/null +++ b/src/15-project-management.md @@ -0,0 +1,21 @@ +# Bigger Projects + +## Stack + +To start a project, you'll want to use *Stack*. Take a look at the docs: <https://docs.haskellstack.org/en/stable/README/> + +Stack takes care of everything from installing the correct compiler over downloading packages to building. + +Install using your package manager, the Windows installer or the command in the docs. + +## Important commands + +- `stack new name` +- `stack build` +- `stack exec` +- `stack ghci` + +## Important files + +- `package.yaml` +- `stack.yaml` \ No newline at end of file diff --git a/work/2021-01-29.hs b/work/2021-01-29.hs new file mode 100644 index 0000000000000000000000000000000000000000..32359f24d296d6c2a9572caea8ab60921b05ef2d --- /dev/null +++ b/work/2021-01-29.hs @@ -0,0 +1,60 @@ +fortytwo = 42 + +rateNumber :: Int -> String +rateNumber 42 = "cool" +rateNumber x + | x < fortytwo = "meh" + | x < 100 = "okay" + | otherwise = "great" + +data BaseColor = Red | Green | Blue deriving (Show, Eq) + +{- +instance Eq BaseColor where + Red == Red = True + Green == Green = True + Blue == Blue = True + _ == _ = False + +-} + +isPartOfYellow :: BaseColor -> Bool +isPartOfYellow Red = True +isPartOfYellow Green = True +isPartOfYellow Blue = False + +isPartOfYellow' :: BaseColor -> Bool +isPartOfYellow' x = case x of + Red -> True + Green -> True + Blue -> False + +quicksort :: [Int] -> [Int] +quicksort [] = [] +quicksort (x:xs) = quicksort (filter (< x) xs) ++ x : quicksort (filter (>= x) xs) + +class Doubleable a where + double :: a -> a + +instance Doubleable Int where + double x = x * 2 + +instance Doubleable [a] where + double list = list ++ list + +data Tree a = Empty | Fork a (Tree a) (Tree a) deriving Show + +instance Functor Tree where + fmap f Empty = Empty + fmap f (Fork x l r) = Fork (f x) (fmap f l) (fmap f r) + +peter :: Tree Int +peter = Fork 3 (Fork 4 Empty Empty) (Fork 6 Empty Empty) + +main :: IO () +-- main = getLine >>= \x -> putStrLn (x ++ x) +main = do + x <- getLine + y <- getLine + putStrLn "hallo" + putStrLn (x ++ x) \ No newline at end of file