Actually Using Haskell

Ashic Mahtab (@ashic)

1 November 2017

Haskell?

Let’s talk about…

  • Scala
  • Go
  • Rust….

Why do we have a compiler?

Yeah yeah, we still need tests…

Abstraction

Project

Templates

stack templates

Stack

  stack new auh [template]
  cd auth
  stack build
  stack exec auh-exe

Adding Dependencies

hpack :)

no-hpack :(

auh.cabal

library
  hs-source-dirs:      src
  exposed-modules:     Lib
  build-depends:       
      base >= 4.7 && < 5
    , hw-kafka-client
    , bytestring
    , time
    , scotty
    , aeson
    , cql-io
    , tinylog
    , cql
    , mtl
    , text

stack.yaml

extra-deps: [hw-kafka-client-2.1.0]

Model

Model.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveDataTypeable #-}

module Model
     where

import GHC.Generics
import Data.Aeson (FromJSON, ToJSON)
import Data.Text

data ToDo = ToDo {id :: Text, description :: Text} deriving (
    Show, Generic)
instance ToJSON ToDo
instance FromJSON ToDo

toDo (identifier, description) = 
  ToDo {Model.id=identifier, description=description}
tupleFromToDo item = (Model.id item, description item)

Expose in auh.cabal

exposed-modules:     
    Lib
  , Model

Use in Lib.hs

{-# LANGUAGE OverloadedStrings #-}

module Lib
    ( someFunc
    ) where

import Model

someFunc :: IO ()
someFunc = putStrLn $ 
           show $ 
           toDo ("something", "description of something")

An Api

Main.hs

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Model
import Data.String
import Web.Scotty

routes = do

    get "/hello" $ text "hello"

    get "/hello/:name" $ do
        name <- param "name"
        text $ fromString $ "Hello " ++ name

main :: IO ()
main = scotty 3000 routes

Doing something “Useful”

Side effects

{-# LANGUAGE OverloadedStrings #-}
module Handlers
    ( whatsTheTime
    ) where

import Data.Time (getCurrentTime)

whatsTheTime :: IO String
whatsTheTime = do
    time <- getCurrentTime
    return $ "The time is now " ++ show time 

Main

get "/time" $ do
    res <- liftIO whatsTheTime
    text $ fromString res

Add me some db

getToDos db =
    map toDo <$>
    cqlQuery ("SELECT id, description from todos.todos;" 
      :: QueryString R() (Text, Text)) () db

Add me some db

getToDos db =
    map toDo <$>
    cqlQuery ("SELECT id, description from todos.todos;" 
      :: QueryString R() (Text, Text)) () db
      
getToDo identifier db =
    fmap toDo <$>
    cqlQuery1 ("SELECT id, description from todos.todos where id=?;" 
        :: QueryString R (Identity Text) (Text, Text)) identifier  db

Add me some db

getToDos db =
    map toDo <$>
    cqlQuery ("SELECT id, description from todos.todos;" 
      :: QueryString R() (Text, Text)) () db
      
getToDo identifier db =
    fmap toDo <$>
    cqlQuery1 ("SELECT id, description from todos.todos where id=?;" 
        :: QueryString R (Identity Text) (Text, Text)) identifier  db
        
upsertToDo item = 
    cqlWrite1 ("INSERT INTO todos.todos (id, description) values (?, ?);" 
        :: QueryString W (Text, Text) ()) $ tupleFromToDo item

Finally… Kafka

record key msg kafka =
    produceMessage kafka record 
    where 
        record = ProducerRecord
                  { prTopic = targetTopic
                  , prPartition = UnassignedPartition
                  , prKey = Just $ B.pack key
                  , prValue = Just $ B.pack msg
                  }

Finally…Kafka

    get "/todos/:p" $ do
        p <- param "p"
        record "access" ("GET /todos/" ++ p) audit
        items <- liftIO $ getToDo (fromString p) c
        json items

    put "/todos" $ do
        record "access" "PUT /todos/" audit
        item <- jsonData :: ActionM ToDo
        _ <- liftIO $ upsertToDo item c
        text "saved successfully"

Thanks

Resources

Slides

https://ashic.github.io/actually-using-haskell/#/

Code

https://github.com/ashic/actually-using-haskell

Book

http://haskellbook.com/ (Christopher Allen)

https://medium.com/@dogwith1eye/setting-up-haskell-in-vs-code-on-macos-d2cc1ce9f60a

archlinux stack fix: https://github.com/commercialhaskell/stack/issues/2712#issuecomment-260804267