Referentially transparent functions Immutable values Controlled side effects Strong, static type system Non-strict (lazy) semantics Extremely expressive syntax which encourages use of abstractions Syntax add :: Int -> Int -> Int add a b = a + b ghci> add 5 2 7 :: Int
another list A convenient structure for recursive functions data [a] = a : [a] | [] data List a = Cons a [a] | Null ghci> [1,2,3] == [1..3] == 1 : 2 : 3 : [] True :: Bool
b) -> [a] -> [b] map _ [] = [] map f (x:xs) = f x : map f xs ghci> map (*2) [1,2,3] [2,4,6] :: [Int] ghci> map (\x -> if even x then 0 else x) [1,2,3] [1,0,3] :: [Int]
too are functions Functions can be passed to other functions as arguments Or returned from function calls apply :: (a -> b) -> a -> b apply f x = f x ghci> apply factorial 5 120 :: Integer
function, you get another function accepting the remaining the arguments. add :: Int -> Int -> Int add a b = a + b ghci> :type add 5 add 5 :: Int -> Int addFive = add 5 ghci> addFive 2 7 :: Int
data Maybe a = Just a | Nothing Maybe is a useful type for representing some kind of failure (like nullable types in imperative languages). How can we use Maybe effectively?
the general type a -> Maybe b, and want to apply them to a value: head [] = Nothing head (x:_) = Just x halfSqrt x = if x < 0 then Nothing else Just (sqrt x / 2) reciprocal 0 = Nothing reciprocal x = Just (1/x) We have isJust and fromJust from Data.Maybe, but we can have more readable code using case statements and pattern matching.
of Nothing -> Nothing Just x -> case halfSqrt x of Nothing -> Nothing Just x -> case reciprocal x of Nothing -> Nothing Just x -> Just x Remember NullPointerExceptions in Java? This is a common idiom in such languages. Haskell can do better.
and a function a -> Maybe b, and returns a Maybe b. joinMaybes :: Maybe a -> (a -> Maybe b) -> Maybe b joinMaybes Nothing _ = Nothing joinMaybes (Just x) f = f x oneOverHalfSqrtHead lst = head lst ‘joinMaybes‘ halfSqrt ‘joinMaybes‘ reciprocal This is a monadic bind function.
Type classes can be compared to interfaces in Java and C#. class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a instance Monad Maybe where x >>= f = joinMaybes x f x >> y = y return x = Just x We can ignore fail.
do x <- getRandom y <- getRandom return (x, y) ghci> evalRand comp (mkStdGen 123) (-1113545701,-1952847176) :: (Int, Int) evalRand :: RandomGen g => Rand g a -> g -> a
in Rand Instead of a random generator, we’re passing the real world newtype IO a = IO (State# RealWorld -> (#State# RealWorld, a#)) getLine :: IO String putStr :: String -> IO ()
"What is your name?" name <- getLine putStrLn ("Hello, "++name++"!") main = putStrLn "What is your name?" >> getLine >>= (\name -> putStrLn ("Hello, "++name++"!"))
of useful functions. putStrLn :: String -> IO () ghci> :type map putStrLn ["Alice", "Bob", "Eve"] [IO ()] sequence :: Monad m => [m a] -> m [a] sequence_ :: Monad m => [m a] -> m () mapM :: Monad m => (a -> m b) -> [a] -> m [b] mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
Monad m => Int -> m a -> m [a] replicateM_ :: Monad m => Int -> m a -> m () ghci> x <- replicateM 3 (putStr "> " >> getLine) > Foo > Bar > Baz ghci> x ["Foo", "Bar", "Baz"] :: [String]