Comments:""
URL:http://dev.stephendiehl.com/hask/#%281%29
- Stephen Diehl ( @smdiehl )
- September 10, 2012
cabal-dev
ghc-pkg check
- Cabal hell is unpleasant.
- Don't force reinstalls.
:r
Code reload:t
Type inspection:k
Kind inspection:i
Instance inspectioncabal install hoogle
cabal install pointfree
cabal install hlint
#~/ghc/ghci.confimport Control.Applicativeimport Control.Monadimport Control.Concurrentimport Control.Concurrent.Asyncimport Control.Parallelimport Data.Stringimport Data.Charimport Data.Listimport Data.Monoidimport Control.Monad.IO.Class-- You must set your prompt to a lambda, it's a law.:set prompt "λ: ":set -fno-warn-unused-imports:def hlint const.return$":! hlint \"src\"":def hoogle \s ->return$":! hoogle --count=15 \""++ s ++"\"":def pl \s ->return$":! pointfree \""++ s ++"\""
Don't learn monads by analogies. Monads are not complicated structures.
classMonad m where (>>=) :: m a -> (a -> m b) -> m b return :: a -> m a
return a >>= f ≡ f a
m >>= return ≡ m
(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
do x <- m
return x
= do m
do y <- return x
f y
= do f x
do b <- do a <- m
f a
g b
= do a <- m
b <- f a
g b
= do a <- m
do b <- f a
g b
do pattern <- expression
morelines
expression >>= (\ pattern ->do morelines)
Desugaring...
main ::IO ()
main =doputStrLn"What is your name: "
name <-getLineputStrLn name
main ::IO ()
main =putStrLn"What is your name:">>=
\_ ->getLine>>=
\name ->putStrLn name
main ::IO ()
main =putStrLn"What is your name: ">>getLine>>= (\name ->putStrLn name)
import Network.HTTP import Data.Functor ((<$>))import Control.Applicative ((<*>))
fetch1, fetch2 ::IOString
fetch1 = simpleHTTP (getRequest "http://www.reddit.com/") >>= getResponseBody
fetch2 = simpleHTTP (getRequest "http://www.google.com/") >>= getResponseBodycombined ::IOString
combined = (++) <$> fetch1 <*> fetch2main ::IO ()
main = combined >>=print
import Prelude hiding (id, (.))import Control.Categoryimport Control.ArrownewtypeF dom cod =F { runF :: (dom -> cod) }instanceArrowFwhere
arr f =F f
first (F f) =F (fst f)wherefst g (a,b) = (g a, b)
second (F f) =F (snd f)wheresnd g (a,b) = (a, g b)instanceCategoryFwhere
(F g) . (F f) =F (g . f)id= arr id
f, g ::FIntInt
f = arr (`div`2)
g = arr (\x -> x*3+1)
main =doprint$ runF (f >>> g) 25
{-# LANGUAGE GADTs #-}dataTerm a whereLit ::Int->TermIntSucc ::TermInt->TermIntIsZero ::TermInt->TermBoolIf ::TermBool->Term a ->Term a ->Term a
import Data.Maybe (fromJust)typeSym=InttypeEnv= [(Sym, Expr)]dataExpr=VarSym|AbsSymExpr|AppExprExpr|LetEnvSymExprderiving(Show)extend ::Env->Sym->Expr->Env
extend env v t = (v,t):enveval ::Env->Expr->Expr
eval env (Var v) = fromJust $lookup v env
eval env (Abs v t) =Let env v t
eval env (App t0 t1) = apply (eval env t0) (eval env t1)
apply (Let e v t0) t1 = eval (extend e v t1) t0-- eval [(1, Var 0)] (Var 1)-- Var 0
Use Haskell functions to represent lambda calculus functions
{-# LANGUAGE GADTs #-}dataExp t whereCon :: t ->Exp tLam :: (Exp s ->Exp t) ->Exp (s -> t)App ::Exp (s -> t) ->Exp s ->Exp tid ::Exp (a -> a)id=Lam (\x -> x)tr ::Exp (a -> b -> a)
tr =Lam (\x -> (Lam (\y -> x))) fl ::Exp (a -> b -> b)
fl =Lam (\x -> (Lam (\y -> y)))
dataExpr b=VarId|LitLiteral|App (Expr b) (Arg b)|Lam b (Expr b)|Let (Bind b) (Expr b)|Case (Expr b) b Type [Alt b]|Cast (Expr b) Coercion|Tick (TickishId) (Expr b)|TypeType|CoercionCoercionderiving (Data, Typeable)
$ ghci -dsuppress-all-ddump-simpl
λ: let x =2.0+3.0
returnIO
(: ((+$fNumInteger (D#2) (D#3)) `cast`...) ([]))
Haskell Propaganda: OOP programming couples code and data together in unnatural ways. Typeclasses are a better way of structuring logic.
classEq a where (==) :: a -> a ->BooleqList :: (Eq a) => [a] -> [a] ->BooleqChar :: (Eq a) =>Char->Char->Bool
$ ghci -dsuppress-all-ddump-simpl
λ: classFoo x
λ: instanceFooInt
$fFooInt
$fFooInt = D:Foo
$fOrdChar (C#'a') (C#'b')$fOrdInteger (__integer 1) (__integer 2)
import Control.Monad.ReaderdataExpr=ValInt|AddExprExpr|VarStringderiving (Show)typeEnv= [(String, Int)]eval ::Expr->ReaderTEnvMaybeInt
eval (Val n) =return n
eval (Add x y) = liftM2 (+) (eval x) (eval y)
eval (Var x) =do env <- ask
val <- lift (lookup x env)return valex ::ReaderTEnvMaybeInt
ex = eval (Add (Val2) (Add (Val1) (Var"x")))main ::IO ()
main =doprint$ runReaderT ex [("x", 2)]print$ runReaderT ex []
I spend half of my time in other languages doing what deriving
in Haskell does automatically.
{-# Language GeneralizedNewtypeDeriving #-}{-# Language StandaloneDeriving #-}{-# Language DeriveDataTypeable #-}{-# Language DeriveFunctor #-}{-# Language DeriveFoldable #-}{-# Language DeriveTraversable #-}import Data.Typeableimport Data.Foldableimport Data.Traversable--------------------------dataColor=Red|Blue|Greenderiving (Show, Eq, Ord)dataAnimal=Dog|Catderiving (Show, Eq, Ord)derivinginstanceTypeableColor--------------------------dataRose a =Rose a [Rose a]deriving (Show, Functor)dataStree a =Tip|Node (Stree a) a (Stree a)deriving (Show, Functor, Foldable, Traversable)--------------------------rosetree ::RoseInt
rosetree =Rose5 [Rose3 [Rose1 [], Rose4[]], Rose7 []]etree ::StreeInt
etree =Node (Node (NodeTip1Tip) 3 (NodeTip4Tip)) 5 (NodeTip7Tip)ctree ::Stree (EitherColorAnimal)
ctree =Node (NodeTip (LeftGreen) Tip) (LeftGreen) (NodeTip (RightDog) Tip) main ::IO ()
main =doprint$fmap (+1) rosetreeprint$fmap (\x ->Rose x []) rosetreelet walk x =if x >25then [x,x] else [x]print$ traverse walk etreeprint$ traverse visitor ctreewhere visitor x =case x ofLeft _ ->RightDogRight _ ->LeftBlue
If you take away nothing else tonight, then try quickcheck.
cabal install quickcheck
import Test.QuickCheckimport Test.QuickCheck.Classesimport Test.QuickCheck.Checkers------------------------------------------------qsort :: [Int] -> [Int]
qsort [] = []
qsort (x:xs) = qsort lhs ++ [x] ++ qsort rhswhere lhs =filter (< x) xs
rhs =filter (>= x) xsprop_maximum :: [Int] ->Property
prop_maximum xs =not (null xs) ==>last (qsort xs) ==maximum xs------------------------------------------------prop_functor ::TestBatch
prop_functor = functor (undefined ::Maybe (Int, Int, Int))prop_monad ::TestBatch
prop_monad = monad (undefined ::Maybe (Int, Int, Int))------------------------------------------------main ::IO ()
main =do
quickCheck prop_maximum
quickBatch prop_functor
quickBatch prop_monad
+++ OK, passed 100 tests.
functor:
identity: +++ OK, passed 500 tests.
compose: +++ OK, passed 500 tests.
monad laws:
left identity: +++ OK, passed 500 tests.
right identity: +++ OK, passed 500 tests.
associativity: +++ OK, passed 500 tests.
import Criterion.Mainimport Criterion.Configfib ::Int->Int
fib 0=0
fib 1=1
fib n = fib (n-1) + fib (n-2)fib2 ::Integer->Integer
fib2 x =truncate$ ( 1/sqrt5 ) * ( phi ^ x - psi ^ x )where
phi = ( 1+sqrt5 ) /2
psi = ( 1-sqrt5 ) /2config ::Config
config = defaultConfig { cfgSamples = ljust 100 }suite :: [Benchmark]
suite = [
bgroup "naive" [
bench "fib 10"$ whnf fib 10
, bench "fib 20"$ whnf fib 20
, bench "fib 30"$ whnf fib 30
],
bgroup "de moivre" [
bench "fib 10"$ whnf fib2 10
, bench "fib 20"$ whnf fib2 20
, bench "fib 30"$ whnf fib2 30
]
]main ::IO ()
main = defaultMainWith config (return ()) suite
$ runhaskell fibber.hs
warming up
estimating clock resolution...
mean is 2.477227 us (320001 iterations)
found 2519 outliers among 319999 samples (0.8%)
1650 (0.5%) high severe
estimating cost of a clock call...
mean is 66.04170 ns (24 iterations)
found 2 outliers among 24 samples (8.3%)
2 (8.3%) high severe
benchmarking naive/fib 10
mean: 114.3386 us, lb 114.1662 us, ub 114.5407 us, ci 0.950
std dev: 958.9434 ns, lb 833.6958 ns, ub 1.158834 us, ci 0.950
{-# LANGUAGE OverloadedStrings, TypeFamilies, DeriveDataTypeable, TemplateHaskell #-}import Data.Acidimport Data.Typeableimport Data.SafeCopyimport Control.Monad.Reader (ask)importqualified Data.Map as Mapimportqualified Control.Monad.State as StypeKey=StringtypeValue=StringdataDatabase=Database!(Map.MapKeyValue)deriving (Show, Ord, Eq, Typeable)$(deriveSafeCopy 0'base ''Database)insertKey ::Key->Value->UpdateDatabase ()
insertKey key value=doDatabase m <- S.get
S.put (Database (Map.insert key value m))lookupKey ::Key->QueryDatabase (MaybeValue)
lookupKey key=doDatabase m <- askreturn (Map.lookup key m)deleteKey ::Key->UpdateDatabase ()
deleteKey key=doDatabase m <- S.get
S.put (Database (Map.delete key m))allKeys ::Int->QueryDatabase [(Key, Value)]
allKeys limit=doDatabase m <- askreturn$take limit (Map.toList m)$(makeAcidic ''Database ['insertKey, 'lookupKey, 'allKeys, 'deleteKey])fixtures ::Map.MapStringString
fixtures = Map.emptytest ::Key->Value->IO ()
test key val =do
database <- openLocalStateFrom "db/" (Database fixtures)
result <- update database (InsertKey key val)
result <- query database (AllKeys10)print resultreturn ()
{-# LANGUAGE DeriveGeneric #-}{-# LANGUAGE OverloadedStrings #-}import Data.Aesonimport Data.Maybeimport GHC.Generics (Generic)importqualified Data.ByteString.Lazy.Char8 as BLdataStruct=Struct { x ::Int, y ::Double } deriving (Show, Generic)instanceFromJSONStructinstanceToJSONStructmain ::IO ()
main =dolet to = decode "{\"y\":3.14,\"x\": 1}" ::MaybeStructlet from = encode $Struct1422.71print$ fromJust to
BL.putStrLn from-- Struct {x = 1, y = 3.14}-- {"y":2.71,"x":142}
{-# LANGUAGE TemplateHaskell #-}import Control.LensdataPoint=Point { _x ::Double, _y ::Double } derivingShow
makeClassy ''Pointadd ::Point->Point->Point
add p q =
p & x +~ q ^. x& y +~ q ^. y
Lens generalizes propertie accessors and mutators.
dataLens a b =Lens { getter :: a -> b, setter :: b -> a -> a }dataLens a b =Lens (a -> b) (b -> a -> a)
import Control.Monadimport Control.Proxy
pairwiseAdd () = runIdentityP $ forever $do
a <- request ()
b <- request ()
respond (a+b)
printer () = runIdentityP $ forever $do
a <- request ()
lift $putStrLn"Output:"
lift $print areadInt () = runIdentityP $ forever $do
n <- lift readLn
respond n
accum n () = runIdentityP $do
replicateM_ n $do
a <- request ()
respond a
lift $putStrLn"Accumulated quota."-- Push vs. Pull-- How many times do we enter a number?
test0 = runProxy $readInt>-> pairwiseAdd >-> accum 2>-> printer ::IO ()-- How about here?
test1 = runProxy $readInt>-> accum 2>-> pairwiseAdd >-> printer ::IO ()
modulePascalwhereimport FFIimport Preludepascal :: [[Int]]
pascal =iterate (\row ->zipWith (+) (0: row) (row ++ [0])) [1]
main = ffi "console.log" (take25 pascal)
// ... // ... Translation of Haskell to Javascript// ... // Built-insthis._ = Fay$$_;this.$ = Fay$$$;this.$fayToJs = Fay$$fayToJs;this.$jsToFay = Fay$$jsToFay;
};
;var main = newPascal();main._(main.Pascal$main);
{-# LANGUAGE OverloadedStrings #-}import Web.Scottyimport Text.Blaze.Html5 hiding (html, param)importqualified Text.Blaze.Html5 as Himport Text.Blaze.Html.Renderer.Text (renderHtml)import Data.Default (def)import Network.Wai.Middleware.Staticimport Network.Wai.Handler.Warp (settingsPort)import Network.HTTP.Types (status404)config ::Options
config = def { verbose =0
, settings = (settings def) { settingsPort =4000 }
}greet ::String->Html
greet user = H.html $do
H.head $
H.title "Welcome!"
H.body $do
H.h1 "Greetings!"
H.p ("Hello ">> toHtml user >>"!")main ::IO ()
main =doputStrLn"Starting HTTP Server."
scottyOpts config $do
middleware $ staticPolicy (noDots >-> addBase "static")
get "/"$
file "index.html"
get "/greet/:name"$do
name <- param "name"
html $ renderHtml (greet name)
Bootstrapping friendly LLVM backend for Haskell based compilers.
{-# LANGUAGE OverloadedStrings #-}{-# LANGUAGE DoRec #-}moduleFactorialwhereimport Text.LLVMfactorial ::Module
factorial =snd$ runLLVM $do
define emptyFunAttrs (iT 32) "factorial" (iT 32) $ \ x ->do"entry"
jump "test"
rec "test"
i <- phi (iT 32) [x `from`"entry", i' `from`"incr"]
acc <- phi (iT 32) [int 1`from`"entry", acc' `from`"incr"]
b <- icmp Iule i (int 1)
br b "exit""incr""incr"
acc' <- mul acc i
i' <- sub i (int 1)
jump "test""exit"
ret acc
main =doprint$ ppModule factorial
$ runhaskell llvm.hs | opt -O3 | llc
factorial: # @factorial
# BB#0: # %entry
movl $1, %eax
cmpl $2, %edi
jb .LBB0_2
.align 16, 0x90
.LBB0_1: # %incr
# =>This Inner Loop Header: Depth=1
imull %edi, %eax
decl %edi
cmpl $1, %edi
ja .LBB0_1
.LBB0_2: # %exit
ret
alex
happy
parsec
epic
bnfc
aterm
harpy
hoopl
llvm
graphsec
pretty-show
hburg
Questions we ask when studying category theory
- What is equality?
- How can express the fundamental relationships between mathematical models?
- SET : Group
- MAN : Lie Group
- TOP : Topological Group
- GRP : Objects
- Can we map algebraic structure onto computation?
- Why am I still single?
- Duality
- Kleisli Categories
- Yoneda Lemma
- Initial algebras and recursion
- Cartesian closed categories
{-# Language RankNTypes #-}{-# Language NoImplicitPrelude #-}classCategory k where id :: k a a (.) :: k b c -> k a b -> k a cdataOp k a b =Op { unOp :: k b a }instanceCategory k =>Category (Op k) whereid=Opid
(Op f) . (Op g) =Op (g . f)dataIso k a b =Iso { to :: k a b, from :: k b a }typeNat k f g = forall a. k (f a) (g a)
Monad Revelation: Monad laws are the category laws for the Kleisli category.
import Control.Monadimport Control.Category-- (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)newtypeK m a b =K { unKleisli :: a -> m b }instance (Monad m) =>Category (K m) whereid=Kreturn
(K g) . (K f) =K (f >=> g)
The field of higher category is still yet to explored in programming.
- Learning Haskell will change the way you think about programming.
- Haskell is where the future is being made today.
- "The future is already here — it's just not very evenly distributed yet."