Haskell and Yesod
Michael Snoyman
What is Haskell?
Note: you can add "by default" after each bullet.
What is Yesod?
Today's talk
We'll focus on three of these strengths:
* Yes, Haskell is user friendly!
Type safety
Full story: http://www.youtube.com/watch?v=0HczswtAVhg
XSS attacks: Description
<script>alert("XSS Attack!")</script>
I was good & I escaped my entities.
XSS attacks: Explained
XSS attacks: Yesod
XSS attacks: Database
Comment
name Text
textualContent Textarea
htmlContent Html
XSS attacks: Form/HTML
commentForm = renderBootstrap $ Comment
<$> areq textField "Name" Nothing
<*> areq textareaField "Textual content" Nothing
<*> areq nicHtmlField "HTML content" Nothing
<p>Name: #{commentName comment}
<p>Textual: #{commentTextualContent comment}
<p>HTML: #{commentHtmlContent comment}
Yes, the namespacing issues here are annoying. It's a downside in Haskell right now, we're hoping to fix it.
XSS attacks: summary
XSS attacks: input/output
Type-safe URLs
Routing (2) blogs <- runDB $ selectList [] []
defaultLayout [whamlet|
<h1>Blog Posts
<ul>
$forall Entity id blog <- blogs
<li>
<a href=@{BlogPostR id}>#{blogTitle blog}
|]
Type-safe URLs: routing
/blog/#BlogId BlogPostR GET
Blog
title Text
slug Text
content Html
UniqueBlog slug
Type-safe URLs: handler
getBlogPostR :: BlogId -> Handler RepHtml
getBlogPostR id = do
blog <- runDB $ get404 id
defaultLayout [whamlet|
<h1>#{blogTitle blog}
<article>#{blogContent blog}
|]
Type-safe URLs: linking
blogs <- runDB $ selectList [] []
defaultLayout [whamlet|
<h1>Blog Posts
<ul>
$forall Entity id blog <- blogs
<li>
<a href=@{BlogPostR id}>#{blogTitle blog}
|]
Type-safe URLs: summary
Type safety: other examples
Concurrency and parallelism
Parallelism
Parallel map
import Control.Parallel.Strategies
someValues = [1..10]
factorial 1 = 1
factorial i = i * factorial (i - 1)
main = do
-- sequential
print $ map factorial someValues
-- parallel
print $ parMap rseq factorial someValues
Other parallelism tools
Concurrency
Example: nodejs file server
http.createServer(function(request, response) {
var uri = url.parse(request.url).pathname;
var filename = path.join(process.cwd(), uri);
path.exists(filename, function(exists) {
if(exists) {
fs.readFile(filename, function(err, data) {
response.writeHead(200);
response.end(data);
});
} else {
util.log('File not found: ' + filename);
response.writeHead(404);
response.end();
}
});
}).listen(3000);
Equivalent Haskell code
main = run 3000 $ \req -> do
let filename = "./" ++ S8.unpack (rawPathInfo req)
exists <- liftIO $ doesFileExist filename
if exists
then return $ ResponseSource status200 []
$ sourceFile' filename
else return $ responseLBS status404 [] "Not found"
sourceFile' = mapOutput (Chunk . fromByteString) . sourceFile
Real Haskell version
main = run 3000 $ \req -> return $ ResponseFile
status200
[]
("./" ++ S8.unpack (rawPathInfo req))
Nothing
Speed comparison
More speed comparison
User friendly
Basic syntax
someValues = [1..10]
factorial 1 = 1
factorial i = i * factorial (i - 1)
main = do
-- sequential
print $ map factorial someValues
DSLs
Full story: http://oreillynet.com/pub/e/2400
Yesod's user friendliness
Templating languages
Questions?