map :: (a -> b) -> [a] -> [b]
type Trace a = Int -> a
traceMap :: (a -> b) -> (Trace a) -> (Trace b)
type BinTree a = Leaf | Fork a (BinTree a) (BinTree a)
binTreeMap :: (a -> b) -> (BinTree a) -> (BinTree b)
fmap :: (a -> b) -> f a -> f b
fmap
to satisfy some properties
fmap id = id
fmap f . fmap g = fmap (f . g)
fmap
is also written as (<$>)
newtype T c = T (c -> Int)
contramap :: Contravariant f => (a -> b) -> f b -> f a
class Functor f => Applicative (f :: * -> *) where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
GHC.Base.liftA2 :: (a -> b -> c) -> f a -> f b -> f c
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
{-# MINIMAL pure, ((<*>) | liftA2) #-}
pure :: a -> f a
puts the a
inside a box<*> :: f (a -> b) -> f a -> f b
lets you use operations inside a boxm10, m20 :: Maybe Int
m10 = pure 10
m20 = pure 20
m10 :: Maybe Int
(+) :: Int -> (Int -> Int)
(+) <$> m10 :: Maybe (Int -> Int)
(+) <$> m10 <*> m20 :: Maybe Int
A -> B
takes some value in A and gives you something in B.getLine :: IO String
getLine
is not a String
. Rather it is a recipe that produces a String
.putStrLn :: String -> IO ()
putStrLn "hello"
is a recipe that produces nothing useful.putStrLn "hello"
is the recipe “write ‘hello’ to the console, and do not produce anything”(>>=) :: IO a -> (a -> IO b) -> IO b
getLine :: IO String
putStrLn :: String -> IO ()
echo :: IO ()
echo = getLine >>= putStrLn
addHello :: String -> String
greet = getLine >>= (putStrLn . addHello)
addHello :: String -> String
addHello name = "Hello, " + name
greet :: IO ()
greet = getLine >>= \name -> putStrLn (addHello name)
main :: IO ()
describes what the program does
main = greet
IO Cake
is like a recipe to produce a Cake
. It is not an actual Cake
.
IO Cake
.IO Cake -> Cake
.(<$>)
(<*>), pure
(>>=)
extract :: IO a -> a
IO a
, instead you use >>=
to channel it to another function.getLine >>=
(\name -> putStrLn ("Hey " ++ name ++ ", you rock!")
putStrLn "Hello, what's your name?" >>=
(\_ -> getLine >>=
(\name -> putStrLn ("Hey " ++ name ++ ", you rock!")
)
)
name <- getLine
is translated to getLine >>= \name -> ...
main = do
putStrLn "Hello, what's your name?"
name <- getLine
putStrLn ("Hey " ++ name ++ ", you rock!")
import Data.Char
putStrLn "Hello, what's your name?" >>=
(\_ -> getLine >>=
(\name -> let bigName = map toUpper name in putStrLn ("Hey " ++ bigName ++ ", you rock!")
)
)
main = do
putStrLn "Hello, what's your name?"
name <- getLine
let bigName = map toUpper name
putStrLn ("Hey " ++ name ++ ", you rock!")
let
or a <-
>>
: a >> b
. First do a
, then do b
. Example putStrLn "Hello" >> putStrLn "Bye"
.
getLine >> getLine
takes two lines from STDIN, ignores the first. See the example below>>
implemented?foo = getLine >> getLine
main = do
secondLine <- foo
putStrLn $ "The second line was: " ++ secondLine
yes = putStrLn "Yes" >> yes
yes1 = forever $ putStrLn "Yes"
isPositive = do
n <- read <$> getLine
if (n > 0)
then putStrLn "positive"
else if (n == 0) then putStrLn "zero"
else putStrLn "negative"
See https://github.com/Agnishom/PRGH17/blob/master/tut4/notes.md