RAM footprint per unit of concurrency (approx)
1.3KB 

2.6 KB 

4.0 KB 

9.0 KB 

64.0 KB 

513 KB 

1024 KB 

General Purpose
Constructors and record accessors become values
Control flow
map(F, [HT]) >
[F(H)map(F, T)];
map(F, []) when is_function(F, 1) > [].
map _ [] = []
map f (x:xs) = f x : map f xs
spec map(Fun, List1) > List2 when
Fun :: fun((A) > B),
List1 :: [A],
List2 :: [B],
A :: term(),
B :: term().
map(F, [HT]) >
[F(H)map(F, T)];
map(F, []) when is_function(F, 1) > [].
map :: (a > b) > [a] > [b]
map _ [] = []
map f (x:xs) = f x : map f xs
spec foldr(Fun, Acc0, List) > Acc1 when
Fun :: fun((Elem :: T, AccIn) > AccOut),
Acc0 :: term(),
Acc1 :: term(),
AccIn :: term(),
AccOut :: term(),
List :: [T],
T :: term().
foldr(F, Accu, [HdTail]) >
F(Hd, foldr(F, Accu, Tail));
foldr(F, Accu, []) when is_function(F, 2) > Accu.
foldr :: (a > b > b) > b > [a] > b
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
%% sum type, 3 possible values
type choice() :: definitely
 possibly
 no_way.
 sum type, 3 possible values
data Choice = Definitely
 Possibly
 NoWay
%% product type, 9 possible values (3 * 3)
type choices() :: {choice(), choice()}.
 product type, 9 possible values (3 * 3)
data Choices = Choices Choice Choice
 as a tuple with a type alias
 NOT THE SAME AS ABOVE! :)
type Choices = (Choice, Choice)
%% record syntax
record(choices,
fst_choice :: choice(),
snd_choice :: choice()).
%% getters need to be implemented manually
spec fst_choice(#choices{}) > choice().
fst_choice(#choices{fst_choices=X}) > X.
spec snd_choice(#choices{}) > choice().
snd_choice(#choices{snd_choices=X}) > X.
 record syntax defines accessors automatically
data Choices =
Choices { fstChoice :: Choice
, sndChoice :: Choice
}
 these getters are automatically defined
fstChoice :: Choices > Choice
fstChoice (Choices { fstChoice = x }) = x
sndChoice :: Choices > Choice
sndChoice (Choices { sndChoice = x }) = x
%% abstract data type for a list
type cons(A) :: nil
 {cons, A, cons(A)}.
 abstract data type for a list
data List a = Nil
 Cons a (List a)
data Choice = Definitely
 Possibly
 NoWay
data Choices = Choices Choice Choice
mkChoices :: Choice > Choice > Choices
mkChoices a b = Choices a b
fstChoice :: Choices > Choice
fstChoice (Choices a _) = a
data Choice = Definitely
 Possibly
 NoWay
data Choices = Choices Choice Choice
mkChoices :: Choice > Choice > Choices
mkChoices a b = Choices a b
fstChoice :: Choices > Choice
fstChoice (Choices a _) = a
 Values can be annotated inline
2 ^ (1 :: Int)
 Bindings can be annotated
success :: a > Maybe a
 Constructors are values
 (and product constructors are functions)
success x = Just x
 Constructors can be pattern matched
 _ is a wildcard
case success True of
Just True > ()
_ > ()
spec is_just({just, A}  nothing) > boolean().
is_just({just, _}) >
true;
is_just(nothing) >
false.
isJust :: Maybe a > Bool
isJust (Just _) = True
isJust Nothing = False
Erlang's pattern matching allows nonlinear patterns.
spec is_equal(A, A) > boolean() when
A :: term().
is_equal(A, A) > true;
is_equal(_, _) > false.
Haskell's... does not.
isEqual :: a > a > Bool
isEqual a b = undefined
This isn't even possible! Only constructors can be pattern matched. Types have no builtin equality.
%% Symbolic operators can be used
%% as functions from the erlang module
erlang:'+'(A, B).
Erlang doesn't have userdefined infix operators
 Symbolic operators can be used
 prefix when in (parentheses)
(+) a b
 Named functions can be used
 infix when in `backticks`
x `elem` xs
 infixl, infixr define associativity
 and precedence (0 lowest, 9 highest)
infixr 5 `append`
a `append` b = a ++ b
spec add(integer(), integer()) > integer().
add(X, Acc) >
X + Acc.
spec sum_fun([integer()]) > integer().
sum_fun(Xs) >
lists:foldl(fun add/2, 0, Xs).
spec sum_lambda([integer()]) > integer().
sum_lambda(Xs) >
lists:foldl(
fun (X, Acc) > X + Acc end,
0,
Xs).
add :: Integer > Integer > Integer
add acc x = acc + x
sumFun :: [Integer] > Integer
sumFun xs = foldl add 0 xs
sumLambda :: [Integer] > Integer
sumLambda xs = foldl (\acc x > acc + x) 0 xs
a > b > c
is really a > (b > c)
f a b
is really (f a) b
add :: Integer > Integer > Integer
add acc x = acc + x
sumFun :: [Integer] > Integer
sumFun xs = foldl add 0 xs
sumLambda :: [Integer] > Integer
sumLambda xs = foldl (\acc x > acc + x) 0 xs
add :: Integer > Integer > Integer
add acc x = acc + x
sumFun :: [Integer] > Integer
sumFun = foldl add 0
sumLambda :: [Integer] > Integer
sumLambda = foldl (\acc x > acc + x) 0
add :: Integer > Integer > Integer
add acc x = (+) acc x
sumFun :: [Integer] > Integer
sumFun = foldl add 0
sumLambda :: [Integer] > Integer
sumLambda = foldl (\acc x > (+) acc x) 0
add :: Integer > Integer > Integer
add acc = (+) acc
sumFun :: [Integer] > Integer
sumFun = foldl add 0
sumLambda :: [Integer] > Integer
sumLambda = foldl (\acc > (+) acc) 0
add :: Integer > Integer > Integer
add = (+)
sumFun :: [Integer] > Integer
sumFun = foldl add 0
sumLambda :: [Integer] > Integer
sumLambda = foldl (+) 0
spec is_negative(number()) > boolean().
is_negative(X) when X < 0 >
true;
is_negative(_) >
false.
isNegative :: (Num a) => a > Bool
isNegative x
 x < 0 = True
 otherwise = False
isNegative :: (Num a) => a > Bool
isNegative x
 x < 0 = True
 otherwise = False
absoluteValue :: (Num a) => a > Bool
absoluteValue x
 isNegative x = x
 otherwise = x
 (), pronounced "unit"
unit :: ()
unit = ()
 Char
someChar :: Char
someChar = 'x'
 Instances of Num typeclass
someDouble :: Double
someDouble = 1
 Instances of Fractional typeclass
someRatio :: Rational
someRatio = 1.2345
some_list() >
[1, 2, 3].
some_other_list() >
[4  [5  [6  []]]].
some_tuple() >
{10, $4}.
some_string() >
"foo".
 [a], type can be written prefix as `[] a`
someList, someOtherList :: [Int]
someList = [1, 2, 3]
someOtherList = 4 : 5 : 6 : []
dontWriteThis = (:) 4 (5 : (:) 6 [])
 (a, b), can be written prefix as `(,) a b`
someTuple, someOtherTuple :: (Int, Char)
someTuple = (10, '4')
someOtherTuple = (,) 4 '2'
 [Char], also known as String
 (also see the OverloadedStrings extension)
someString :: String
someString = "foo"
Erlang doesn't have typeclasses.
Elixir has Protocols, which are closer, but they are also not typeclasses.
class Equals a where
isEqual :: a > a > Bool
instance Equals Choice where
isEqual Definitely Definitely = True
isEqual Possibly Possibly = True
isEqual NoWay NoWay = True
isEqual _ _ = False
instance (Equals a) => Equals [a] where
isEqual (a:as) (b:bs) = isEqual a b &&
isEqual as bs
isEqual as bs = null as && null bs
{
class Eq a where
(==) :: a > a > Bool
}
instance Eq Choice where
Definitely == Definitely = True
Possibly == Possibly = True
NoWay == NoWay = True
_ == _ = False
data Choice = Definitely
 Possibly
 NoWay
deriving (Eq)
data Choice = Definitely
 Possibly
 NoWay
deriving ( Eq, Ord, Enum, Bounded
, Show, Read )
prop_itsthere() >
?FORALL(I,int(),
[I] == queue:to_list(
queue:cons(I,
queue:new()))).
import Data.Sequence ((>), empty)
import Data.Foldable (toList)
prop_itsthere :: Int > Bool
prop_itsthere i = [i] == toList (empty > i)
$ ghci
λ> import Test.QuickCheck
λ> import Data.Foldable
λ> import Data.Sequence
λ> quickCheck (\i > [i :: Int] ==
toList (empty > i))
+++ OK, passed 100 tests.
spec main([string()]) > ok.
main(_Args) >
{ok, Secret} = file:read_file("/etc/passwd"),
file:write_file("/tmp/passwd", Secret),
ok.
main :: IO ()
main = do
secret < readFile "/etc/passwd"
writeFile "/tmp/passwd" secret
return ()
do m
 desugars to:
m
do a < m
return a
 desugars to:
m >>= \a > return a
do m
return ()
 desugars to:
m >> return ()
main :: IO ()
main = do
secret < readFile "/etc/passwd"
writeFile "/tmp/passwd" secret
return ()
main :: IO ()
main =
readFile "/etc/passwd" >>= \secret > do
writeFile "/tmp/passwd" secret
return ()
main :: IO ()
main =
readFile "/etc/passwd" >>= \secret >
writeFile "/tmp/passwd" secret >>
return ()
main :: IO ()
main =
readFile "/etc/passwd" >>= \secret >
writeFile "/tmp/passwd" secret
main :: IO ()
main =
readFile "/etc/passwd" >>=
writeFile "/tmp/passwd"
spec flat_map(fun((A) > [B]), [A]) > [B] when
A :: term(),
B :: term().
flat_map(F, Xs) > [ Y  X < Xs, Y < F(X) ].
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = [ y  x < xs, y < f x ]
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = do
x < xs
y < f x
return y
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = do
x < xs
f x
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = xs >>= \x > f x
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = xs >>= f
flatMap :: (a > [b]) > [a] > [b]
flatMap f xs = flip (>>=) f xs
flatMap :: (a > [b]) > [a] > [b]
flatMap = flip (>>=)
flatMap :: (a > [b]) > [a] > [b]
flatMap = (=<<)
$ runhaskell help
Usage: runghc [runghc flags] [GHC flags] module [program args]
The runghc flags are
f /path/to/ghc Tell runghc where GHC is
help Print this usage information
version Print version number
$ ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
Loading package ghcprim ... linking ... done.
Loading package integergmp ... linking ... done.
Loading package base ... linking ... done.
h>
:t
shows type information
h> :t map
map :: (a > b) > [a] > [b]
h> :t map (+1)
map (+1) :: Num b => [b] > [b]
h> :t (>>=)
(>>=) :: Monad m => m a > (a > m b) > m b
:i
shows typeclass info
h> :i Num
class Num a where
(+) :: a > a > a
(*) :: a > a > a
() :: a > a > a
negate :: a > a
abs :: a > a
signum :: a > a
fromInteger :: Integer > a
 Defined in `GHC.Num'
instance Num Integer  Defined in `GHC.Num'
instance Num Int  Defined in `GHC.Num'
instance Num Float  Defined in `GHC.Float'
instance Num Double  Defined in `GHC.Float'
:i
shows value info
h> :info map
map :: (a > b) > [a] > [b]
 Defined in `GHC.Base'
h> :info (>>=)
class Monad m where
(>>=) :: m a > (a > m b) > m b
...
 Defined in `GHC.Base'
infixl 1 >>=
:i
shows type info
h> :info Int
data Int = ghcprim:GHC.Types.I#
ghcprim:GHC.Prim.Int#
 Defined in `ghcprim:GHC.Types'
instance Bounded Int  Defined in `GHC.Enum'
instance Enum Int  Defined in `GHC.Enum'
instance Eq Int  Defined in `GHC.Classes'
instance Integral Int  Defined in `GHC.Real'
instance Num Int  Defined in `GHC.Num'
instance Ord Int  Defined in `GHC.Classes'
instance Read Int  Defined in `GHC.Read'
instance Real Int  Defined in `GHC.Real'
instance Show Int  Defined in `GHC.Show'
:l
load a module
:r
to reload
h> :! echo 'hello = print "hello"' > Hello.hs
h> :l Hello
[1 of 1] Compiling Main ( Hello.hs, interpreted )
Ok, modules loaded: Main.
h> hello
"hello"
h> :! echo 'hello = print "HELLO"' > Hello.hs
h> :r
[1 of 1] Compiling Main ( Hello.hs, interpreted )
Ok, modules loaded: Main.
h> hello
"HELLO"
 WordCount1.hs
main :: IO ()
main = do
input < getContents
let wordCount = length (words input)
print wordCount
 WordCount2.hs
main :: IO ()
main =
getContents >>= \input >
let wordCount = length (words input)
in print wordCount
 WordCount3.hs
main :: IO ()
main = getContents >>= print . length . words
>>=
?do
is just syntax sugar for the >>=
(bind) operator.main
, the Haskell runtime will evaluate these actions
 Function composition
(.) :: (b > c) > (a > b) > a > c
f . g = \x > f (g x)
 Function application (with a lower precedence)
($) :: (a > b) > a > b
f $ x = f x
map f (map g xs) = map (f . g) xs
{# RULES
"ByteString specialise break (x==)" forall x.
break ((==) x) = breakByte x
"ByteString specialise break (==x)" forall x.
break (==x) = breakByte x
#}
{# RULES
"ByteString specialise break (x==)" forall x.
break ((==) x) = breakByte x
"ByteString specialise break (==x)" forall x.
break (==x) = breakByte x
#}
import Data.ByteString.Char8 (ByteString, break)
splitLine :: ByteString > (ByteString, ByteString)
splitLine = break (=='\n')
{# RULES
"ByteString specialise break (x==)" forall x.
break ((==) x) = breakByte x
"ByteString specialise break (==x)" forall x.
break (==x) = breakByte x
#}
import Data.ByteString.Char8 (ByteString, break)
splitLine :: ByteString > (ByteString, ByteString)
splitLine = breakByte '\n'
 [1..] is an infinite list, [1, 2, 3, ...]
print (head (map (*2) [1..]))
 [1..] is an infinite list, [1, 2, 3, ...]
print (head (map (*2) [1..]))
 Outside in, print x = putStrLn (show x)
putStrLn (show (head (map (*2) [1..]))
 Outside in, print x = putStrLn (show x)
putStrLn (show (head (map (*2) [1..]))
 head (x:_) = x
 map f (x:xs) = f x : map f xs
 desugar [1..] syntax
putStrLn (show (head (map (*2) (enumFrom 1))))
 desugar [1..] syntax
putStrLn (show (head (map (*2) (enumFrom 1))))
 enumFrom n = n : enumFrom (succ n)
putStrLn (show (head (map (*2)
(1 : enumFrom (succ 1)))))
 enumFrom n = n : enumFrom (succ n)
putStrLn (show (head (map (*2)
(1 : enumFrom (succ 1)))))
 apply map
putStrLn (show (head
((1*2) :
map (*2) (enumFrom (succ 1)))))
 apply map
putStrLn (show (head ((1*2) : …)))
 apply head
putStrLn (show (1*2))
 apply head
putStrLn (show (1*2))
 show pattern matches on its argument
putStrLn (show 2)
 show pattern matches on its argument
putStrLn (show 2)
 apply show
putStrLn "2"
if' :: Bool > a > a > a
if' cond a b = case cond of
True > a
False > b
(&&) :: Bool > Bool > Bool
a && b = case a of
True > b
False > False
const :: a > b > a
const x = \_ > x
fib :: [Integer]
fib = 0 : 1 : zipWith (+) fib (tail fib)
cycle :: [a] > [a]
cycle xs = xs ++ cycle xs
iterate :: (a > a) > a > [a]
iterate f x = x : iterate f (f x)
takeWhile :: (a > Bool) > [a] > [a]
takeWhile _ [] = []
takeWhile p (x:xs)
 p x = x : takeWhile p xs
 otherwise = []
h> let f x = head True
<interactive>:23:16:
Couldn't match expected type `[a0]' with actual type `Bool'
In the first argument of `head', namely `True'
In the expression: head True
In an equation for `f': f x = head True
h> let f x = heads True
<interactive>:24:11:
Not in scope: `heads'
Perhaps you meant one of these:
`reads' (imported from Prelude), `head' (imported from Prelude)
h> let x = x in x
 Infinite recursion, not a fun case to deal with!
h> case False of True > ()
*** Exception: <interactive>:29:124: Nonexhaustive patterns in case
h> head []
*** Exception: Prelude.head: empty list
h> error "this throws an exception"
*** Exception: this throws an exception
h> undefined
*** Exception: Prelude.undefined
 Polymorphic and recursive
data List a = Cons a (List a)
 Nil
deriving (Show)
data Tree a = Leaf a
 Branch (Tree a) (Tree a)
deriving (Show)
listMap :: (a > b) > List a > List b
listMap _ Nil = Nil
listMap f (Cons x xs) = Cons (f x) (listMap f xs)
treeToList :: Tree a > List a
treeToList root = go root Nil
where
 Note that `go` returns a function!
go (Leaf x) = Cons x
go (Branch l r) = go l . go r
module List where
data List a = Cons a (List a)
 Nil
instance (Eq a) => Eq (List a) where
(Cons a as) == (Cons b bs) = a == b && as == bs
Nil == Nil = True
_ == _ = False
instance Functor List where
fmap _ Nil = Nil
fmap f (Cons x xs) = Cons (f x) (fmap f xs)
{# LANGUAGE DeriveFunctor #}
module List where
data List a = Cons a (List a)
 Nil
deriving (Eq, Functor)
import Data.List (sort)
newtype Down a = Down { unDown :: a }
deriving (Eq)
instance (Ord a) => Ord (Down a) where
compare (Down a) (Down b) = case compare a b of
LT > GT
EQ > EQ
GT > LT
reverseSort :: Ord a => [a] > [a]
reverseSort = map unDown . sort . map Down
class Monoid a where
mempty :: a
mappend :: a > a > a
instance Monoid [a] where
mempty = []
mappend = (++)
infixr 6 <>
(<>) :: (Monoid a) => a > a > a
(<>) = mappend
class Functor f where
fmap :: (a > b) > f a > f b
instance Functor [] where
fmap = map
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap _ Nothing = Nothing
infixl 4 <$>
(<$>) :: Functor f => (a > b) > f a > f b
(<$>) = fmap
class (Functor f) => Applicative f where
pure :: a > f a
infixl 4 <*>
(<*>) :: f (a > b) > f a > f b
instance Applicative [] where
pure x = [x]
fs <*> xs = concatMap (\f > map f xs) fs
instance Applicative Maybe where
pure = Just
Just f <*> Just x = Just (f x)
_ <*> _ = Nothing
class Monad m where
return :: a > m a
(>>=) :: m a > (a > m b) > m b
(>>) :: m a > m b > m b
ma >> mb = ma >>= \_ > mb
instance Monad [] where
return = pure
m >>= f = concatMap f m
instance Monad Maybe where
return = pure
Just x >>= f = f x
Nothing >>= _ = Nothing
{# LANGUAGE OverloadedStrings #}
module SJSON where
import Prelude hiding (concat)
import Data.Text (Text, concat)
import Data.Attoparsec.Text
import Control.Applicative
data JSON = JArray [JSON]
 JObject [(Text, JSON)]
 JText Text
deriving (Show)
pJSON :: Parser JSON
pJSON = choice [ pText, pObject, pArray ]
where
pString = concat <$> "\"" .*> many pStringChunk <*. "\""
pStringChunk = choice [ "\\\"" .*> pure "\""
, takeWhile1 (not . (`elem` "\\\""))
, "\\" ]
pText = JText <$> pString
pPair = (,) <$> pString <*. ":" <*> pJSON
pObject = JObject <$> "{" .*> (pPair `sepBy` ",") <*. "}"
pArray = JArray <$> "[" .*> (pJSON `sepBy` ",") <*. "]"
{# LANGUAGE ForeignFunctionInterface #}
import Foreign.C.Types
import Control.Monad
foreign import ccall unsafe "stdlib.h rand"
c_rand :: IO CUInt
main :: IO ()
main = replicateM_ 20 (c_rand >>= print)
 FlipImage.hs
import System.Environment
import Data.Word
import Data.Array.Repa hiding ((++))
import Data.Array.Repa.IO.DevIL
import Data.Array.Repa.Repr.ForeignPtr
main :: IO ()
main = do
[f] < getArgs
(RGB v) < runIL $ readImage f
rotated < (computeP $ rot180 v) :: IO (Array F DIM3 Word8)
runIL $ writeImage ("flip"++f) (RGB rotated)
rot180 :: (Source r e) => Array r DIM3 e > Array D DIM3 e
rot180 g = backpermute e flop g
where
e@(Z :. x :. y :. _) = extent g
flop (Z :. i :. j :. k) =
(Z :. x  i  1 :. y  j  1 :. k)
import Control.Concurrent
import Network.HTTP
getHTTP :: String > IO String
getHTTP url = simpleHTTP (getRequest url) >>= getResponseBody
urls :: [String]
urls = map ("http://ifconfig.me/"++) ["ip", "host"]
startRequest :: String > IO (MVar ())
startRequest url = do
v < newEmptyMVar
forkIO (getHTTP url >>= putStr >> putMVar v ())
return v
main :: IO ()
main = do
mvars < mapM startRequest urls
mapM_ takeMVar mvars
A monad is just a monoid in the category of endofunctors, what's the problem?
Terminology from category theory can be intimidating (at first)!
return
probably doesn't mean what you think it means.
sum :: Num a => [a] > a
sum [] = 0
sum (x:xs) = x + sum xs
sum :: Num [a] => [a] > a
sum = go 0
where
go acc (x:xs) = go (acc + x) (go xs)
go acc [] = acc
sum :: Num [a] => [a] > a
sum = go 0
where
go acc _
 seq acc False = undefined
go acc (x:xs) = go (acc + x) (go xs)
go acc [] = acc
{# LANGUAGE BangPatterns #}
sum :: Num [a] => [a] > a
sum = go 0
where
go !acc (x:xs) = go (acc + x) (go xs)
go acc [] = acc
Slides 

Source 

bob@redivi.com 
