├── .gitignore ├── 01-getting-started ├── my-project.cabal ├── src │ ├── Assignments.hs │ └── Main.hs └── stack.yaml ├── 02-importing-code ├── my-project.cabal ├── src │ ├── Assignment.hs │ └── Main.hs └── stack.yaml ├── 03-using-monads ├── my-project.cabal ├── src │ ├── Assignments.hs │ └── Main.hs └── stack.yaml ├── 04-rest-api ├── my-project.cabal ├── src │ ├── Assignments.hs │ └── Main.hs └── stack.yaml ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .stack* 2 | dist/ 3 | -------------------------------------------------------------------------------- /01-getting-started/my-project.cabal: -------------------------------------------------------------------------------- 1 | name: my-project 2 | version: 0.1.0.0 3 | synopsis: My first Haskell Project 4 | description: Please see README.md 5 | license: BSD3 6 | author: Your name here 7 | maintainer: your.address@example.com 8 | category: Web 9 | build-type: Simple 10 | cabal-version: >=1.10 11 | 12 | executable my-project 13 | hs-source-dirs: src 14 | main-is: Main.hs 15 | default-language: Haskell2010 16 | build-depends: base 17 | -------------------------------------------------------------------------------- /01-getting-started/src/Assignments.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = do 3 | name <- getLine 4 | putStrLn (greet name) 5 | 6 | greet :: String -> String 7 | greet name = "Hello " ++ name ++ "!" 8 | 9 | -------------------------------------------------------------------------------- /01-getting-started/src/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | main :: IO () 4 | main = do 5 | putStrLn (greet "bobby") 6 | putStrLn (greet "World") 7 | 8 | greet name = "Hello " ++ name ++ "!" 9 | -------------------------------------------------------------------------------- /01-getting-started/stack.yaml: -------------------------------------------------------------------------------- 1 | flags: {} 2 | packages: 3 | - '.' 4 | extra-deps: [] 5 | resolver: lts-3.1 6 | -------------------------------------------------------------------------------- /02-importing-code/my-project.cabal: -------------------------------------------------------------------------------- 1 | name: my-project 2 | version: 0.1.0.0 3 | synopsis: My first Haskell Project 4 | description: Please see README.md 5 | license: BSD3 6 | author: Your name here 7 | maintainer: your.address@example.com 8 | category: Web 9 | build-type: Simple 10 | cabal-version: >=1.10 11 | 12 | executable my-project 13 | hs-source-dirs: src 14 | main-is: Main.hs 15 | default-language: Haskell2010 16 | build-depends: base, 17 | time, 18 | aeson 19 | -------------------------------------------------------------------------------- /02-importing-code/src/Assignment.hs: -------------------------------------------------------------------------------- 1 | module Assignment where 2 | 3 | import Data.Aeson (encode) 4 | 5 | list :: [Int] 6 | list = [1,2,3,4] 7 | 8 | main :: IO () 9 | main = do 10 | print (encode list) 11 | -------------------------------------------------------------------------------- /02-importing-code/src/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Data.Time (getCurrentTime) 4 | import System.IO (readFile) 5 | 6 | main = do 7 | putStrLn (greet "bobby") 8 | putStrLn (greet "World") 9 | printTime 10 | 11 | greet name = "Hello " ++ name ++ "!" 12 | 13 | printNumbers = do 14 | putStrLn (show (3+4)) 15 | 16 | printConfig = do 17 | contents <- readFile "stack.yaml" 18 | putStrLn contents 19 | 20 | printTime = do 21 | time <- getCurrentTime 22 | putStrLn (show time) 23 | 24 | -------------------------------------------------------------------------------- /02-importing-code/stack.yaml: -------------------------------------------------------------------------------- 1 | flags: {} 2 | packages: 3 | - '.' 4 | extra-deps: [] 5 | resolver: lts-3.1 6 | -------------------------------------------------------------------------------- /03-using-monads/my-project.cabal: -------------------------------------------------------------------------------- 1 | name: my-project 2 | version: 0.1.0.0 3 | synopsis: My first Haskell Project 4 | description: Please see README.md 5 | license: BSD3 6 | author: Your name here 7 | maintainer: your.address@example.com 8 | category: Web 9 | build-type: Simple 10 | cabal-version: >=1.10 11 | 12 | executable my-project 13 | hs-source-dirs: src 14 | main-is: Main.hs 15 | default-language: Haskell2010 16 | build-depends: base 17 | -------------------------------------------------------------------------------- /03-using-monads/src/Assignments.hs: -------------------------------------------------------------------------------- 1 | import Control.Monad (replicateM_) 2 | import System.IO (readLn) 3 | import System.Environment (getArgs) 4 | 5 | -- implement unix cat command 6 | main = do 7 | args <- getArgs 8 | case args of 9 | [path] -> do 10 | contents <- readFile path 11 | putStrLn contents 12 | _ -> do 13 | putStrLn "Usage: cat ./path/to/file.abc" 14 | 15 | -- print out message N times 16 | message :: IO () 17 | message = do 18 | putStrLn "Type message:" 19 | msg <- getLine 20 | putStrLn "Type # times:" 21 | n <- readLn 22 | replicateM_ n (putStrLn msg) 23 | -------------------------------------------------------------------------------- /03-using-monads/src/Main.hs: -------------------------------------------------------------------------------- 1 | main = do 2 | let action = putStrLn "Hello World" 3 | action 4 | action 5 | action 6 | return () 7 | 8 | beCareful :: Maybe Int 9 | beCareful = do 10 | Just 6 11 | -- putStrLn "oops" 12 | Nothing 13 | return 5 14 | 15 | sayHello :: IO String 16 | sayHello = do 17 | name <- getLine 18 | putStrLn ("Hello " ++ name) 19 | return name 20 | -------------------------------------------------------------------------------- /03-using-monads/stack.yaml: -------------------------------------------------------------------------------- 1 | flags: {} 2 | packages: 3 | - '.' 4 | extra-deps: [] 5 | resolver: lts-3.1 6 | -------------------------------------------------------------------------------- /04-rest-api/my-project.cabal: -------------------------------------------------------------------------------- 1 | name: my-project 2 | version: 0.1.0.0 3 | synopsis: A JSON API! 4 | description: Please see README.md 5 | license: BSD3 6 | author: Your name here 7 | maintainer: your.address@example.com 8 | category: Web 9 | build-type: Simple 10 | cabal-version: >=1.10 11 | 12 | executable my-project 13 | hs-source-dirs: src 14 | main-is: Main.hs 15 | default-language: Haskell2010 16 | build-depends: base, 17 | scotty, 18 | aeson 19 | -------------------------------------------------------------------------------- /04-rest-api/src/Assignments.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | 4 | import Data.Monoid ((<>)) 5 | import Data.Aeson (FromJSON, ToJSON) 6 | import GHC.Generics 7 | import Web.Scotty 8 | 9 | data User = User { userId :: Int, userName :: String } deriving (Show, Generic) 10 | instance ToJSON User 11 | instance FromJSON User 12 | 13 | bob :: User 14 | bob = User { userId = 1, userName = "bob" } 15 | 16 | jenny :: User 17 | jenny = User { userId = 2, userName = "jenny" } 18 | 19 | allUsers :: [User] 20 | allUsers = [bob, jenny] 21 | 22 | matchesId :: Int -> User -> Bool 23 | matchesId id user = userId user == id 24 | 25 | main = do 26 | putStrLn "Starting Server..." 27 | 28 | scotty 3000 $ do 29 | get "/hello/:name" $ do 30 | name <- param "name" 31 | text ("hello " <> name <> "!") 32 | 33 | get "/users" $ do 34 | json allUsers 35 | 36 | get "/users/:id" $ do 37 | id <- param "id" 38 | json (filter (matchesId id) allUsers) 39 | 40 | -- assignment: post user and print it out 41 | post "/users" $ do 42 | user <- jsonData :: ActionM User 43 | json user 44 | -------------------------------------------------------------------------------- /04-rest-api/src/Main.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | {-# LANGUAGE DeriveGeneric #-} 3 | 4 | module Main where 5 | 6 | import Data.Monoid ((<>)) 7 | import Data.Aeson (FromJSON, ToJSON) 8 | import GHC.Generics 9 | import Web.Scotty 10 | 11 | data User = User { userId :: Int, userName :: String } deriving (Show, Generic) 12 | instance ToJSON User 13 | instance FromJSON User 14 | 15 | bob :: User 16 | bob = User { userId = 1, userName = "bob" } 17 | 18 | jenny :: User 19 | jenny = User { userId = 2, userName = "jenny" } 20 | 21 | allUsers :: [User] 22 | allUsers = [bob, jenny] 23 | 24 | matchesId :: Int -> User -> Bool 25 | matchesId id user = userId user == id 26 | 27 | main = do 28 | putStrLn "Starting Server..." 29 | scotty 3000 $ do 30 | get "/hello/:name" $ do 31 | name <- param "name" 32 | text ("hello " <> name <> "!") 33 | 34 | get "/users" $ do 35 | json allUsers 36 | 37 | get "/users/:id" $ do 38 | id <- param "id" 39 | json (filter (matchesId id) allUsers) 40 | -------------------------------------------------------------------------------- /04-rest-api/stack.yaml: -------------------------------------------------------------------------------- 1 | flags: {} 2 | packages: 3 | - '.' 4 | extra-deps: [] 5 | resolver: lts-3.1 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Sean Hess (c) 2015 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Sean Hess nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Source code for [Practical Haskell tutorials](http://seanhess.github.io/2015/08/04/practical-haskell-getting-started.html) 2 | --------------------------------------------------------------------------------