On Github igraves / haskell_talk
fst (x,y) = y fst (5+5,1+1) == 2
5+5? Never evaluated.
foo :: Int -> Int foo i = putStrLn i --Nope
Effects outside the type are not allowed.
True == 1 -- Won't type check
Types are strict. Implicit coercion isn't allowed. Relations between non-matching types must be specified.
y :: Int y = 1 f x = x f y -- Typechecker determines f :: Int -> Int
The typechecker fills in the gaps on types for you.
f x = x --Identity not False = True --Explicit matching not True = False f g x = g x -- Higher order
--Identity y x = x y = \z -> z --Both of the above are equivalent to each other
--Apply incr to 1 and bind that to y y = incr 1 -- y == 2
Giving a function its argument is called "applying it to its argument".
incr :: Int -> Int incr x = x + 1
add :: Int -> Int -> Int add a b = a + b
add3 :: Int -> Int -> Int -> Int add3 a b c = a + b + c
incr :: Int -> Int incr = add 1
If a function isn't given all its all of its arguments, a new function that takes the remaining arguments is given instead of a result.
x :: [Int] x = [1,2,3,4] --equivalent definition. Empty list at the end of cons's x = 1 : 2 : 3 : 4 : [] y = [5] -- z == [1,2,3,4,5] Append z = x ++ y
type String = [Char] -- "abc" == 'a' : 'b' : 'c' : []
Above is a type synonym declaration.
id :: a -> a filter :: (a -> Bool) -> [a] -> [a] map :: (a -> b) -> [a] -> [b]
--Mapping over lists, most generally map :: (a -> b) -> [a] -> [b]
Variables with the same name are one type. Variables with different names are not assumed to be the same type.
data Color = Red | Green | Blue --import Data.Word --Word8 is an unsigned byte --newtype only allows one type constructor data HexColor = RGB Word8 Word8 Word8 | White | Black -- .... RGB :: Word8 -> Word8 -> Word8 -> HexColor White :: HexColor Red :: Color
-- A pair tuple (5,6.0) :: (Int, Double) -- a 3-tuple ("hi",7,'a') :: (String, Int, Char)
Tuples can be about as long as you want.
-- A simple something or nothing data Maybe a = Nothing | Just a -- Can be singly recursive like a list data List a = Cons a (List a) | Nil -- Can be doubly recursive like a tree data Tree a = Node (Tree a) a (Tree a) | Leaf --Binary Tree -- Can have more than one type in our containers data Either a b = Left a | Right b
-- Matching a Boolean as before, explicitly not :: Bool -> Bool not True = False --True is a data constructor we match against not False = True --List cons matching head :: [a] -> a head [] = error "Oh no!" head (a:as) = a str_hex :: HexColor -> String str_hex White = "White" str_hex Black = "Black" --Lets bind the RGB values to variables --Show turns things to String, more on that later str_hex (RGB c1 c2 c3) = "RGB " ++ (show c1) ++ " " ++ (show c2) ++ " " ++ (show c3)
--Given some function that gets a value from Maybe a --Encountering nothing will fail fromJust :: Maybe a -> a fromJust (Just x) = x --Or the list head case, empty list fails head :: [a] -> a head (x:xs) = x
If a function can't match your patterns, the program will crash. Handling situations like this is up to the developer.
class Show a where show :: a -> String --Actual Show has two other methods --But you only need show to be minimally complete class Ord a where compare :: a -> a -> Ordering (<) :: a -> a -> Bool (>=) :: a -> a -> Bool --A number of others class Eq a where (==) :: a -> a -> Bool
Classes in Haskell are like Interfaces in Java, Protocols in Objective-C, or abc's in Python(?).
instance Show Color where show Red = "Red" show Green = "Green" show Blue = "Blue" -- Or you can derive Show to get the equivalent functionality to the above data Color = Red | Green | Blue deriving (Show) -- This only works if you have nullary constructors OR, all types for each -- constructor are themselves already in Show (basic types usually are)
class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b -- (>>) is (>>=) such that a >>= (\_ -> b) -- We'll ignore it from here on
Monads are "contexts in which we can run computations" that have particular useful traits that allow us to model side-effects in a meaningful way.
Monads are wrapper types like the ones that we saw earlier (Maybe a).
return :: a -> m aReturn takes a value and wraps it in the context of the monad. Enables you to place values into a monad so you can use them inside the monad.
(>>=) :: m a -> (a -> m b)Runs the monad on the left to get its result of type a Gives that result to the function on the right Constructs continuting monadic function to run
m a >>= (a -> m b) >>= (b -> m c) :: m c
Anything that is an instance of Monad must obey the following laws
Left Identity
return a >>= f ~= f a
Right Identity
m >>= return ~= m
Associativity
(m >>= f) >>= g ~= m >>= (\x -> f x >>= g)