Pursuing the strong, not so silent type
A Haskell story
by Katie Miller (@codemiller) Software Engineer at Facebook
"The limits of my language mean the limits of my world"
- Ludwig Wittgenstein
strong static types
Source: Ruin Raider on Flickr, CC BY-NC-ND 2.0
more than 1 million requests/second
def haskell_spammer(user, friend, post) if talking_about_haskell(post) && num_common_friends(user, friend) < 5 && most_friends_like_ruby(friend) block_post else do_nothing end end
continuous deployment
FXL
functional
efficient data fetching
automatic batching and concurrency
HaskellSpammer = If (TalkingAboutHaskell(postContent) && NumCommonFriends(userId, friendId) < 5 && MostFriendsLikeRuby(friendId)) Then BlockAction Else @[]
NumCommonFriends(x, y) = Length(Intersect(FriendsOf(x), FriendsOf(y)))
20x speedup
Haskell
Is Haskell academic?
Source: https://xkcd.com/1312
reasoning about code
haskellSpammer :: Haxl Bool haskellSpammer = talkingAboutHaskell .&& numCommonFriends .< 5 .&& mostFriendsLikeRuby
where mostFriendsLikeRuby = do friends <-‐ getFriends rubyFriends <-‐ filterM friendLikesRuby friends return (length rubyFriends >= length friends `div` 2)
friendLikesRuby friend = hasAssoc friend likeAssoc rubyPage
user-defined data types
hasAssoc :: Int -‐> Int -‐> Int -‐> Bool hasAssoc id assoc target = ...
hasAssoc :: Int -‐> Int -‐> Int -‐> Bool hasAssoc id assoc target = ...
newtype Id = Id Int newtype AssocId = AssocId Int
hasAssoc :: Int -‐> Int -‐> Int -‐> Bool hasAssoc id assoc target = ...
newtype Id = Id Int newtype AssocId = AssocId Int
hasAssoc :: Id -‐> AssocId -‐> Id -‐> Bool hasAssoc id assoc target = ...
data Language = Ruby | Haskell | Php
data Language = Ruby | Haskell | Php
likesLanguage :: Language -‐> Id -‐> Bool
data Language = Ruby | Haskell | Php
likesLanguage :: Language -‐> Id -‐> BoollikesLanguage Ruby userId = hasAssoc userId likesAssoc 1995 || hasAssoc userId likesAssoc 2005
data Language = Ruby | Haskell | Php
likesLanguage :: Language -‐> Id -‐> BoollikesLanguage Ruby userId = hasAssoc userId likesAssoc 1995 || hasAssoc userId likesAssoc 2005likesLanguage Haskell userId = hasAssoc userId likesAssoc 42
data Language = Ruby | Haskell | Php
likesLanguage :: Language -‐> Id -‐> BoollikesLanguage Ruby userId = hasAssoc userId likesAssoc 1995 || hasAssoc userId likesAssoc 2005likesLanguage Haskell userId = hasAssoc userId likesAssoc 42likesLanguage Php _ = False
Is Haskell difficult to learn?
expectations
Is Haskell a panacea?
blockAustralians :: Haxl SyncResponses blockAustralians = do textMap <-‐ textArr let text = HashMap.lookupDefault "" "main_text" textMap numBadWords = length $ filter (`Text.isInfixOf` text) aussieTerms numBadPhrases = length $ filter (`Text.isInfixOf` text) aussieSayings if numBadWords < 2 && numBadPhrases <= 0 then return noResponses else if numBadWords < 4 && numBadPhrases < 2 then return requireCaptcha else if numBadWords < 5 && numBadPhrases < 3 then return $ responses [warnUser, requireCaptcha] else if numBadWords < 7 && numBadPhrases < 4 then return warnUser else if numBadWords < 8 && numBadPhrases < 5 then return $ responses [warnUser, blockAccess] else if numBadWords < 10 && numBadPhrases < 6 then return blockAccess else if numBadWords < 13 && numBadPhrases < 7 then return $ responses [ blockAccess , enrollInFakeAccountCheckpoint ] else return $ responses [ blockAccess , enrollInFakeAccountCheckpoint , requireCaptcha ]
where aussieTerms = [ "Acca Dacca" , "ambo" , "arvo" , "Aussie" , "bangaroo"
blockAustralians :: Haxl SyncResponses blockAustralians = do textMap <-‐ textArr let text = HashMap.lookupDefault "" "main_text" textMap numBadWords = length $ filter (`Text.isInfixOf` text) aussieTerms numBadPhrases = length $ filter (`Text.isInfixOf` text) aussieSayings if numBadWords < 2 && numBadPhrases <= 0 then return noResponses else if numBadWords < 4 && numBadPhrases < 2 then return requireCaptcha else if numBadWords < 5 && numBadPhrases < 3 then return $ responses [warnUser, requireCaptcha] else if numBadWords < 7 && numBadPhrases < 4 then return warnUser else if numBadWords < 8 && numBadPhrases < 5 then return $ responses [warnUser, blockAccess] else if numBadWords < 10 && numBadPhrases < 6 then return blockAccess else if numBadWords < 13 && numBadPhrases < 7 then return $ responses [ blockAccess , enrollInFakeAccountCheckpoint ] else return $ responses [ blockAccess , enrollInFakeAccountCheckpoint , requireCaptcha ]
where aussieTerms = [ "Acca Dacca" , "ambo" , "arvo" , "Aussie" , "bangaroo"
results
ideas worth pursuing
community
Haxl team past and present
Louis Brandy
Jonathan Coens
Andrew Farmer
Kubo Kováč
Jake Lengyel
Simon Marlow
Katie Miller
Bartosz Nitka
Jon Purdy
Aaron Roth
Zejun Wu
Noam Zilberstein
More about Haxl
Haxl on GitHub
'Fighting spam with Haskell' blog post
'There is no Fork' ICFP paper and presentation
'The Road to Running Haskell at Facebook Scale' presentation
Wired article
The End
by Katie Miller (@codemiller) Software Engineer at Facebook