Slide 1

Slide 1 text

overloading semicolons swift -> haskell Vlad Ki @darkproger

Slide 2

Slide 2 text

@kievfprog

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

struct Team {} struct Tournament {} func runTournament(_ tournament: Tournament) -> Team { let teams = tournament.joinTeams(); let groups = tournament.emitGroups(teams); let groupResults = groups.map(tournament.runGroup); let brackets = tournament.buildBracket(groupResults); NSLog("%@", brackets); let winner = tournament.eliminate(brackets); return winner; }

Slide 8

Slide 8 text

Distinct Haskell Features → laziness (non-strict eval, call-by-need) → pure, referentially-transparent functions → enables equational reasoning

Slide 9

Slide 9 text

Laziness is Awesome

Slide 10

Slide 10 text

Why FP Matters, John Hughes 1990: Modularity within eps (a:b:rest) | abs(a-b) <= eps = b | otherwise = within eps (b:rest) easydiff f x h = (f(x+h) − f x)/h differentiate h0 f x = map (easydiff f x) (repeat (/2) h0) within eps (differentiate h0 f x)

Slide 11

Slide 11 text

Graphs data Node = A | B | C | D | E | F | G | H | I | J | K | L | M | N deriving (Show, Enum, Bounded, Eq) edge from to = case (from, to) of (A, B) -> Just 4 (A, E) -> Just 6 (A, D) -> Just 7 -- ...

Slide 12

Slide 12 text

reachable :: Node -> [Node] reachable from = catMaybes [fmap (const to) (edge from to) | to <- enum]

Slide 13

Slide 13 text

type Trace = [Node] data Path = Path Int Trace deriving (Show, Eq) instance Ord Path where (Path a _) <= (Path b _) = a <= b

Slide 14

Slide 14 text

Build the tree of all possible paths! bruteforce :: Int -> Trace -> Node -> Node -> Tree Path bruteforce cost trace to from = Tree (Path cost trace') (map build (reachable from)) where trace' = from:trace build = bruteforce (cost + fromJust (edge from n)) trace' to

Slide 15

Slide 15 text

Shortest path is easy, right? path == minimum (last (Tree.levels (bruteforce N A)))

Slide 16

Slide 16 text

Branch and Bound data Bound a = Bound a | Unknown deriving (Show, Eq) -- | Unlike Maybe's Ord this one steers away from Unknown instance (Eq a, Ord a) => Ord (Bound a) where -- ...

Slide 17

Slide 17 text

btw: cost must grow monotonically as you go down

Slide 18

Slide 18 text

minbranch :: Ord a => Tree a -> Bound a minbranch = minbranch' Unknown minbranch' :: Ord a => Bound a -> Tree a -> Bound a minbranch' bound (Tree.Node root subs) = case subs of [] -> Bound root _ -> foldr f bound subs where f sub@(Tree.Node r _) b | Bound r <= b = branch' b sub | otherwise = b -- **prune !!!**

Slide 19

Slide 19 text

Ok, back to Dota2!

Slide 20

Slide 20 text

struct Team {} struct Tournament {} func runTournament(_ tournament: Tournament) -> Team { let teams = tournament.joinTeams(); let groups = tournament.emitGroups(teams); let groupResults = groups.map(tournament.runGroup); let brackets = tournament.buildBracket(groupResults); NSLog("%@", brackets); let winner = tournament.eliminate(brackets); return winner; }

Slide 21

Slide 21 text

a slight syntax conversion data Team data Tournament runTournament (tournament :: Tournament) = let teams = joinTeams tournament groups = emitGroups tournament teams groupResults = map (runGroup tournament) teams brackets = buildBracket tournament groupResults _ = nsLog brackets winner = eliminate tournament brackets in (winner :: Team)

Slide 22

Slide 22 text

nsLog will never be executed! data Team data Tournament runTournament (tournament :: Tournament) = let teams = joinTeams tournament groups = emitGroups tournament teams groupResults = map (runGroup tournament) teams brackets = buildBracket tournament groupResults _ = nsLog brackets winner = eliminate tournament brackets in (winner :: Team)

Slide 23

Slide 23 text

let's bring back data dependencies data Team data Tournament runTournament (τ :: Tournament) = joinTeams τ ! (\teams -> emitGroups τ teams ! (\groups -> map (runGroup τ) teams ! (\groupResults -> buildBracket τ groupResults (\brackets -> nsLog brackets ! (\_ -> eliminate τ brackets (\winner -> winner))))))

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

what type should have? perhaps ! :: a -> (a -> b) -> b

Slide 26

Slide 26 text

what type should have? sanity check: nsLog :: Show a => a -> Int nsLog x = callCFunction "NSLog" "%@" x test = let action = nsLog "hello" in x ! (\_ -> x) * not referentially transparent!

Slide 27

Slide 27 text

let's come up with a type for effects data Effects a = {- constructor for a computation that returns a value of type `a' -} ! :: Effects a -> (a -> Effects b) -> Effects b ! a f = {- perform computation `a', then feed its result to `f' which will give a computation `b' -} unit :: a -> Effects a unit a = {- make `a' pretend to be a computation -}

Slide 28

Slide 28 text

data Team data Tournament runTournament :: Tournament -> Effects Team runTournament τ = joinTeams τ ! (\teams -> emitGroups τ teams ! (\groups -> map (runGroup τ) groups (\groupResults -> buildBracket τ groupResults (\brackets -> nsLog brackets ! (\_ -> eliminate τ brackets (\winner -> unit winner))))))

Slide 29

Slide 29 text

Sugar: do runTournament τ = do teams <- joinTeams τ groups <- emitGroups τ groupResults <- mapM (runGroup τ) groups brackets <- buildBracket τ groupResults nsLog brackets winner <- eliminate τ brackets unit winner

Slide 30

Slide 30 text

a monad, where = >>= class Functor f where fmap :: (a -> b) -> f a -> f b class Functor m => Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b also, m has kind * -> *: HKT!

Slide 31

Slide 31 text

map in a monad mapM :: Monad m => (a -> m b) -> [a] -> m [b] mapM f [] = return [] mapM f (x:xs) = f x >>= \x' -> mapM f xs >>= \xs' -> return (x':xs')

Slide 32

Slide 32 text

what about the rest of the functions? runTournament τ = do teams <- joinTeams τ groups <- emitGroups τ groupResults <- mapM (runGroup τ) groups brackets <- buildBracket τ groupResults nsLog brackets winner <- eliminate τ brackets unit winner

Slide 33

Slide 33 text

meh joinTeams = Ѕ༼ ϑ ༽ꙷ emitGroups = Ѕ༼ ϑ ༽ꙷ runGroup = Ѕ༼ ϑ ༽ꙷ buildBracket = Ѕ༼ ϑ ༽ꙷ eliminate = Ѕ༼ ϑ ༽ꙷ

Slide 34

Slide 34 text

types first data Group data GResult data Team data Bracket data ElimResult

Slide 35

Slide 35 text

types first data TournamentOps next = JoinTeams ([Team] -> next) | EmitGroups [Team] ([Group] -> next) | RunGroup Group (GResult -> next) | BuildBracket [GResult] (Bracket -> next) | Eliminate Bracket (ElimResult -> next)

Slide 36

Slide 36 text

Free Monads ∀ f:Functor you have a simplest way to construct a Monad data Free f a = Return a | Free (f (Free f a))

Slide 37

Slide 37 text

a free functor instance Functor f => Functor (Free f) where fmap f x = case x of Return a -> Return (f a) Free as -> Free (fmap (fmap f) as)

Slide 38

Slide 38 text

and a free monad for every free functor instance Functor f => Monad (Free f) where return = Return (>>=) :: Free f a -> (a -> Free f b) -> Free f b x >>= f = case x of Return a -> f a Free as -> Free (fmap (>>= f) as)

Slide 39

Slide 39 text

lifting to Free liftF :: Functor f => f a -> Free f a liftF = Free . fmap return act x = liftF . flip x () -- `act' for action fun0 x = liftF (x id) fun1 x = liftF . flip x id

Slide 40

Slide 40 text

what about the rest? joinTeams = fun0 JoinTeams emitGroups = fun1 EmitGroups runGroup = fun1 RunGroup buildBracket = fun1 BuildBracket eliminate = fun1 Eliminate

Slide 41

Slide 41 text

we have a program tree now!

Slide 42

Slide 42 text

let's interpret it evalDemo :: Free Tournament ElimResult -> ElimResult evalDemo program = case program of Return x -> x Free (JoinTeams f) -> evalDemo (f mkTeam) Free (EmitGroups a f) -> evalDemo (f mkSomeGroup) Free (RunGroup (Group (w:r:_)) f) -> evalDemo (f (GResult w r)) Free (BuildBracket a f) -> evalDemo (f bracket3Demo) Free (Eliminate a f) -> evalDemo (f (Winner (Team 1)))

Slide 43

Slide 43 text

https://gist.github.com/proger/2961ca8e84c2b9637f576b449d008caf {-# LANGUAGE NoMonomorphismRestriction, NoImplicitPrelude, ScopedTypeVariables, StandaloneDeriving, RebindableSyntax #-}

Slide 44

Slide 44 text

chatbots data Query data Input data Dialog next = Ask Query (Input -> next) bot :: [Input] -> Free Dialog Input -> Int bot answers program = case program of Return x -> x Free (Ask q f) -> case answers of (x:xs) -> bot xs (f x) [] -> error "lol"

Slide 45

Slide 45 text

a blast from the past DSLs in objc era regularExpressionWithPattern: predicateWithFormat: constraintsWithVisualFormat: make.left.equalTo(superview.mas_left) .with.offset(padding.left)

Slide 46

Slide 46 text

why do this in a strict language? → OCaml's LWT: https://mirage.io/wiki/tutorial-lwt let start c = Lwt.join [ (Time.sleep_ns (Duration.of_sec 1) >>= fun () -> C.log c "Heads"); (Time.sleep_ns (Duration.of_sec 2) >>= fun () -> C.log c "Tails") ] >>= fun () -> C.log c "Finished"

Slide 47

Slide 47 text

how about a GPU DSL?

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

canny :: Float -> Float -> Acc (Image RGBA32) -> (Acc (Image Float), Acc (Vector Int)) canny (constant -> low) (constant -> high) = stage1 . nonMaximumSuppression low high . gradientMagDir low . gaussianY . gaussianX . toGreyscale where stage1 x = (x, selectStrong x) → accelerate

Slide 50

Slide 50 text

free monads over common types https://gist.github.com/leftaroundabout/ 144da39e1084d61b10ba603e5951de81

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

equational reasoning: isomophisms and univalence

Slide 54

Slide 54 text

data Nat = Z | Succ Nat

Slide 55

Slide 55 text

data Maybe a = Nothing | Just a data List a = Nil | Cons a (List a)

Slide 56

Slide 56 text

data Fix f = Fix (f (Fix f)) data L a b = Nil | Cons a b type List a = Fix (L a) Nat ∼ Fix Maybe

Slide 57

Slide 57 text

data Free f a = Return a | Free (f (Free f a)) data Const c a = Const c data Free (Const c) a = Pure a | Free (Const c) data Either c a = Right a | Left c

Slide 58

Slide 58 text

Decision Trees Are Free Monads Over the Reader Functor Clay Thomas https://clathomasprime.github.io/hask/freeDecision

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

is all of this going to be in Swift? → probably not → but wait

Slide 61

Slide 61 text

Neural Networks Grenade (ad) TensorFlow PyTorch DLVM: Modern Compiler Infrastructure for Deep Learning Systems, dlvm.org

Slide 62

Slide 62 text

Automatic Differentiation

Slide 63

Slide 63 text

// Staged function representing f(x, w, b) = dot(x, w) + b let f: Rep<(Float2D, Float2D, Float1D) -> Float2D> = lambda { x, w, b in x • w + b } // Staged function ’g’, type-inferred from ’f’ let g = lambda { x, w, b in let linear = f[x, w, b] // staged function application return tanh(linear) } // Gradient of ’g’ with respect to arguments ’w’ and ’b’ let dg = gradient(of: g, withRespectTo: (1, 2), keeping: 0) // ’dg’ has type: // Rep<(Float2D, Float2D, Float1D) -> (Float2D, Float2D, Float2D)> // Call staged function on input data ’x’, ’w’ and ’b’ let (dg_dw, dg_db, result) = dg[x, w, b]

Slide 64

Slide 64 text

No content