Skip to content

Instantly share code, notes, and snippets.

@PutziSan
Last active July 24, 2018 08:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PutziSan/b0f625cf4082f616932629209032a68c to your computer and use it in GitHub Desktop.
Save PutziSan/b0f625cf4082f616932629209032a68c to your computer and use it in GitHub Desktop.
Haskell notes

haskell

Notes for learning haskell

ToDo

weitermachen bei http://learnyouahaskell.com/recursion

basics

notes from the help-cmd-tool (haskell landing-page) + learnyouahaskell.com

  • E-V-E-R-Y-T-H-I-N-G is a function

list

  • [1, '2'] => ERROR : a list can contain only one single type
  • [2,4,8,10] !! 2 => 8 : !! extracts item by index from an array
  • 1 : [] => [1] the colone-func (:) adds a value at the head of a list
  • [2,4] ++ [8,10] => [2,4,8,10] : ++ concats two arrays
  • [3,2] > [2,3] => True ; [2,2] > [2,1] => True : When using <, <=, > and >= to compare lists, they are compared in lexicographical order. First the heads are compared. If they are equal then the second elements are compared, etc.
  • head, tail, last, init, length, reverse, take, drop => array-funcs (siehe auch gute dokus von ramda zu funktionalitäten)
  • null [] => True : checks for empty list
  • elem 3 [1,2,3]=> True : check if first var is in given list (siehe auch infix-funktionen)
  • further List-funcs
  • cycle [1,2] => [1,2,1,2,...]; repeat 1 => [1,1,1,...] : produces infinite lists

strings == a list of chars

  • a char defined via single quote ', a string via double quote "
  • a string is a list of chars => ['h', 'i'] == "hi"
  • 'h' != "h", da "h" == ['h']
  • 'a' : "sap" => "asap" == ['a', 's', 'a', 'p'] : add the char 'a' to the char-list ['s', 'a', 'p'] == "sap"

range-operator ..

  • [first,sec..end] => füllt ein array mit der vorschrift: [first,first + step,first + 2 * step,…end] wobei step = sec - first
  • [1..4] => [1,2,3,4] : here sec is implicitly set to sec = first + 1
  • Doku allgemein zu 'arithmetic sequence'
  • can be used if the items implement Enum (read morein the documentation) (in principle strings with a-z and integer; double possible but not necessarily good)

variables

  • let x = 4 in x * x => 16 : define variables and give them scope (in just separates the expression from the body.)
  • let villain = (28,"chirs") in fst villain => 28 : returns first value of per variable defined tuple (see variables below for syntax)

extract variables via patterns

  • let (a,b) = (10,12) in a * 2 => 20 : (10,12) is matched against pattern (a,b) and so a resolves to 10
  • let (a,_,_) = (10,12,13) in a * 2 => 20 : _ is ignore-operator and can be used multiple in tuple- and list-patterns
  • let (a:b:c:[]) = "xyz" in a => x : whereby let (a:b:c:[]) == let (a:b:c) (see list for the colone-func)
    • (a:b:c:d) is short-hand for (a:(b:(c:d))) : so a is the first from b, which is the first from c and c is the rest
    • let (a:[]) = "xyz" in a => x
    • let (a:_) = "xyz" in a => x
  • let ab@(a,b) = (10,20) in (ab,a,b) => ((10,20),10,20) : VAR@... saves the original value of the pattern-matches in VAR

tuples

  • (28, "JP") => ... : keep a bunch of values together, (can contain different types)
  • fst (28, "JP") => 28 : returns the first val of a tuple
  • wenn shape of object is clear : tuple > list, zb, store x-y-coods:
    • A: [[1,2],[2,3]] vs B: [(1,2),(2,3)] =>
    • B > A, da
      • [[1,2],[2,3,4]] => no error for haskell
      • [(1,2),(2,3,4)] => haskell-error
  • singleton-tuple ((1)) does not exist

functions

  • let square x = x * x in square 3 => 9
    • let square x = x * x entspricht quasi (JS) const square = x => x * x
    • in (siehe #variables) nutzt die vorher definierte funktion square als higher order function
  • + is a function (writing + (function) as plus for clarity) : let plus a b = a + b (second + ist die arithmetische operation)
  • most haskell-functions are curried, so plus (1) (2) == plus (1, 2) where plus 1 == plus (1) returns a function (added braces for clarity)
  • map (+1) [1..4] => [2,3,4,5] : map is global library-func, so map (+1) [1..4] == map (plus 1) [1...4]
  • 3 `elem` [1,2,3] => True : using elem-func (list) with the infix-operator

where

  • <expression> where <bindings>
  • get1 = x where x=1 ; get1 => 1 : define variables after usage
  • calcSum a b = sum' a b where sum' c d = c + d : where can also define functions
  • where is no expression, so it cannot be used in expressions (somehow "only in functions") => see let ... in below

where bindings can also be nested. It's a common idiom to make a function and define some helper function in its where clause and then to give those functions helper functions as well, each with its own where clause.

let ... in

  • let <bindings> in <expression>
  • let x=1 in x+3 => 4
  • let ... in is an expression and can be used nearly everywhere
    • 4 * (let a = 9 in a + 1) + 2 => 42
    • [let square x = x*x in (square 2, square 6)] => [4,36]
  • let a=2; b=6; in a*b => 12 : semicolons can sperate serval inline variables
  • other differntations (where/let):
  • [add1 | a <- [1..4], let add1 = a+1] => [2,3,4,5] : The names defined in a let inside a list comprehension are visible to the output function (the part before the |)

List comprehension

  • abgeleitet von math. Notation: { 2x | x ∈ ℕ, x ≤ 10 } => [x*2 | x <- [1..10]] => [2,4,...,20]
  • [FUNCTION | DEFINITIONEN, NEBENBEDINGUNGEN, ...]
    • FUNCTION => wie sollen die einzelnen Elemente sein
    • DEFINITIONEN => nach Format x <- ...
    • CONSTRAINTS (Nebenbedingungen) => function (x `mod` 7 == 3, x < 5, ...)
  • composition: [ [ x | x <- xs, even x ] | xs <- [[1,2],[2,4]]] => [[2],[2,4]]
    • da FUNCTION pro ele ist kann man es entsprechend composen
  • use with pattern matching for variables: [a+b | (a,b) <- [(1,2),(6,9)] => [3,15]

function pattern matching

basic

is42 :: (Integral a) => a -> String
is42 42 = "is 42"
is42 x = "not 42"

this is syntactic suggar for a normal case expression:

is42 :: (Integral a) => a -> String
is42 n = case n of
  42 -> "is 42"
  n -> "not 42"

guards

detailedIs42 :: (Integral a) => a -> String
detailedIs42 numb
  | numb < 42 = "too low"
  | numb == 42 = "is 42"
  | otherwise = "too high"

types

  • :t 'a' => 'a' :: Char : :t returns the type
  • > 1 params: add x y = x + y, type-def: add :: Int -> Int -> Int
    • => no diff between return-type + params (last type is return type) => see currying

read and show are functions, show is like a toString and read a bit like the opposite from show (reads the string and tries to get a type (Int, list, ...) from string) show 3 => "3", read "5" - 1 => 4 (read MUST be directly used afterwards or you have to add eplicit type annotations (see below))

type annotations

  • type annotations begins with ::
  • can be inlined read "5" :: Int and (read "5" :: Float) * 4

type variables / polymorphic functions

  • :t head => head :: [a] -> a : a here is a type variable and can be any type
  • functions that have type variables are called polymorphic

Typeclasses / class constraints

  • a bit like interfaces in OOP
  • :t (==) => (Eq a) => a -> a -> Bool
    • Everything before the =>-Operator is called a class constraint (Nebenbedingung)
    • contraints for a type definition defines how the type variables have to look like
    • eg Eq a means that every following a MUST have the same type
    • basic typeclasses:
      • Eq e.g. :t (==) => (Eq a) => a -> a -> Bool
      • Ord e.g. (>) :: (Ord a) => a -> a -> Bool (type must have a ordering)
      • Show e.g. show :: Show a => a -> String (type must presentable as string) ! the show-fn (lowercased!) is like toString; show 3 => "3"
      • Read e.g. read :: Read a => String -> a (like opposite of Show/show); reads the string and tries to get a type (Int, list, ...) from string
      • Enum e.g. succ :: Enum a => a -> a : Enum-Nebenbedingung meint dass der Typ Numerierbar (bzw eine interne Ordnung haben muss)
      • Bounded e.g. minBound :: Bounded a => a : Type must have an upper and lower bound (maxBound- and minBound-fn)
      • Num e.g. :t 42 => 42 :: (Num t) => t and (*) :: (Num a) => a -> a -> a (product eg in 2*2)
      • Integral : includes Int and Integer (hat nicht mit einem eigentlichen Integral zu tun)
      • Floating : Float and Double

working with stack

get started

see documentation

unter windows empfiehlt stack in C:\sr-stack o.ä. zu installieren da osnst die langen Pfade zu Problemen führen können stack#3285 (ebenso auch die project-root für haskell-folder)

  1. ... init stack-prject (see docu)
  2. stack build builds your app => stack build --file-watch => watch-mode
  3. stack exec [YOUR_PROJECT_NAME]-exe execute

for VS Code with haskero: you need to install intero (stack build intero)

modules

Lib.hs:

module Lib (someExportFunc, otherExport) where

-- possible type-annotations:
someExportFunc :: IO ()
-- the func:
someExportFunc = putStrLn 'hello world'

-- [...] private implementation-funcs
privateFunc = "this will not be exported"

-- weitere export-funcs
otherExport x = x * x

Main.hs

module Main where

import Lib

main :: IO ()
main = someFunc
  • module MODULE_NAME (EXPORT_NAME_1, ...) where => defines the moduleName and which functions it will export
  • module MODULE_NAME where will export every defined function in the file

tools

code prettifier

web-frameworks/libraries

allgemein:

  • dieser aritkel scheint den anschein zu amche ndas haskell deutlich weniger leisten könnte (aber zum anfang sollte das nicht so wichtig oder problematisch sein)

fjeden ToCheck:

  • yesod
    • good starting point for web => scheint älteste und "robusteste" zu sein
    • scheint aber komplettes web-framework zu sein (MVC-bla)
  • servant
    • angeblich speziell für REST-Apis sehr gut
    • scheint gutes bonus-set zu haben (auto-generate API-Docs in swagger, JS client, mock server, documentation)
  • spock
    • im allgemeinen gilt spock > scotty, scheint aber nicht mehr so aktiv weiterentwickelt zu werden
    • müsste man sich weiter anschauen

SQL (mySQL, PostgreSQL)

good article which mentions a lot of different libs

List from the best to the worst (after the comments, no further own experiences currently)

examples

recursion

length' :: (Num b) => [a] -> b
length' [] = 0
length' (_:xs) = 1 + length' xs
factorial :: (Integral a) => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)

guards

max' :: (Ord a) => a -> a -> a
max' a b
    | a > b     = a
    | otherwise = b
myCompare :: (Ord a) => a -> a -> Ordering
a `myCompare` b
    | a > b     = GT
    | a == b    = EQ
    | otherwise = LT

this example includes the backticks (`myCompare`) for readability

where

initials :: String -> String -> String
initials firstname lastname = [f] ++ ". " ++ [l] ++ "."
    where (f:_) = firstname
          (l:_) = lastname
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment