-- * installing
-- - GHC (which version?)
-- - Haskell platform
-- (from haskell.org/platform)
-- (note the directions for OSX Mavericks)
-- - GHC
-- (from haskell.org/ghc, H. Platform is GHC + robust library versions)
-- (new version came out today!)
-- * file structure
module Main where
-- * basic syntax
-- - functions
-- - types (::)
-- - data types
-- - let
-- - case
-- top level definitions
factorial :: Int -> Int
factorial 0 = 1
factorial n = n * factorial (n - 1)
factorial' :: Int -> Int
factorial' n = case n of
0 -> 1
n -> let n' = n - 1
result :: Int
result = n * factorial n'
in result
cons :: a -> [a] -> [a]
cons x xs = x:xs
mainBasic :: IO ()
mainBasic = return ()
main :: IO ()
main = putStrLn (show (factorial' 3))
-- * running a haskell program
-- - runhaskell or runghc -- both look for (main :: IO ())
-- - ghc also looks for (main :: IO ())
-- - ghci -- doesn't require main, can interactively evaluate
-- (use ghci!)
-- * types
-- - datatypes
-- - newtypes
-- - type aliases
-- - deriving (when we get to type classes)
-- Q: what is a?
-- A: it's a type variable
-- A: analagous to OCaml (a MyList)
-- type 'a MyList = Nil | Cons of ('a * 'a MyList)
-- OCaml 'type' == Haskell 'data'
-- OCaml 'type' /= Haskell 'type'
data MyList a = Nil | Cons a (MyList a)
-- deriving (Show)
-- deriving (Eq, Ord, Show)
-- ^^ extremely common, ommitted because we will write our own instance for
-- Show
toHaskellList :: MyList a -> [a]
toHaskellList Nil = []
toHaskellList (Cons x xs) = x : toHaskellList xs
instance (Show a) => Show (MyList a) where
show ml = show (toHaskellList ml)
myLength :: MyList a -> Int
myLength Nil = 0
myLength (Cons _ xs) = 1 + myLength xs
someList :: MyList Int
someList = Cons 1 Nil
-- newtypes have a single constructor, with a single contained type
newtype MyOtherList a = ConMyOtherList (MyList a)
type MyListAlias a = MyList a
myLength' :: MyListAlias a -> Int
myLength' = myLength
-- this does not work
-- myLength' :: MyOtherList a -> Int
-- myLength' = myLength
-- * type classes
-- - classes
-- - instances
-- - functions with constraints
-- - (perhaps discuss objects vs type classes as exists vs forall)
-- class declarations declare the "interface"
-- what would a custom version of Show look like?
class MyShow a where
myshow :: a -> String
-- think of type classes as interfaces
-- show cannot have this type:
-- show :: forall a. a -> String
-- note the "forall a" annotation is valid syntax if you put
-- {-# LANGUAGE RankNTypes #-} at the top of the file
-- why not? how do you show a function?
-- why not return ""
-- show really is "almost" universal
-- show :: (Show a) => a -> String
-- right now, MyList is not showable
data FunWrapper a b = MakeFunction (a -> b)
-- deriving (Show) -- will not work!
-- lets play with monoids!
class MyMonoid a where
unit :: a
times :: a -> a -> a
-- don't forget the laws!
-- times x unit = x
-- times unit x = x
instance MyMonoid Int where
unit = 1
times x y = x * y
-- equivalently
-- times = (*)
-- or
-- times x y = (*) x y
-- be careful evaluating [mexponent 2 3] in ghci. It will give you an
-- error if you don't fix the type of 2, like so: [mexponent (2 :: Int) 3]
mexponent :: (MyMonoid a) => a -> Int -> a
mexponent x 0 = unit
mexponent x n = times x (mexponent x (n-1))
instance MyMonoid [a] where
unit = []
times xs ys = xs ++ ys
-- check the laws!
-- [] ++ ys == ys -- check
-- xs ++ [] == xs -- check
-- * monads
-- - definition
-- - do notation
-- - lightweight exceptions (partial vs total programming)
class MyMonad m where
-- think "pure a -> effectful a"
-- you can think of IO for effectful
-- the built in Monad class calls these return and (>>=)
return' :: a -> m a
-- you might like to have this function
-- run :: m a -> a
-- this does not exist!!!
bind1' :: m a -> (a -> m b) -> m b
bind2' :: (a -> m b) -> (m a -> m b)
bind2' f aM = bind1' aM f
-- bind1' and bind2' have the same type if you flip the arguments
-- data Maybe a = Nothing | Just a
-- -- OCaml terminology would be
-- data Option a = None | Some a
instance MyMonad Maybe where
-- you can write these signatures
-- if you put {-# LANGUAGE InstanceSigs #-} at the top of the file
-- return' :: a -> Maybe a
return' x = Just x
-- bind1' :: Maybe a -> (a -> Maybe b) -> Maybe b
bind1' Nothing f = Nothing
bind1' (Just a) f = f a
-- look up strings associated with 1, 2, 3, and concatenate them.
-- returns nothing if either 1, 2 or 3 are not in the list
complicated :: [(Int, String)] -> Maybe String
complicated things = case lookup 1 things of
Nothing -> Nothing
Just s1 -> case lookup 2 things of
Nothing -> Nothing
Just s2 -> case lookup 3 things of
Nothing -> Nothing
Just s3 -> Just (s1 ++ s2 ++ s3)
complicated2 :: [(Int, String)] -> Maybe String
complicated2 things =
lookup 1 things >>= \ s1 ->
lookup 2 things >>= \ s2 ->
lookup 3 things >>= \ s3 ->
return (s1 ++ s2 ++ s3)
complicated3 :: [(Int, String)] -> Maybe String
complicated3 things = do
s1 <- lookup 1 things
s2 <- lookup 2 things
s3 <- lookup 3 things
-- the syntax of let changes inside of 'do notation'
let result = s1 ++ s2 ++ s3
-- note there is no 'in' keyword
return result
-- last note: check out haskell.org/hoogle
-- we didn't get to these topics...
--
-- * laziness
-- - infinite data structures
-- - weak-head-normal form
-- * IO
-- - printing
-- - user input
-- - fully evaluating a computation
-- * helpful tools
-- - hackage docs
-- - prelude source