Quantcast
Channel: Hacker News 50
Viewing all articles
Browse latest Browse all 9433

Article 49

$
0
0

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 inspection
  • cabal 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
Don't read the monad tutorials. No really, don't read the monad tutorials. Learn about Haskell types. Learn what a typeclass is. Read the Typeclassopedia. Read the monad definitions. Use monads in real code. Don't write monad-analogy tutorials.
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)

Stream programming model

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."

Viewing all articles
Browse latest Browse all 9433

Trending Articles