PureScript Workshop for JSConf MedellΓn
Lesson 1: Getting Started
Install psc-package and pulp
npm i -g psc-package pulp
Initialize the project
Build the project
Do your happy dance!
My first PureScript project πΊ
Part 2: Resources and Creating a Bundle
PureScript by Example (Free eBook)
Let's Build a Simon Game in PureScript
PureScript Cheatsheet
PureScript Slack Channel
Creat an index.html at the root of your directory
Add basic html markup
<!DOCTYPE html>
< html lang ="en ">
< head >
< meta charset ="UTF-8 ">
< meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
< meta http-equiv ="X-UA-Compatible " content ="ie=edge ">
< title > Document</ title >
</ head >
< body >
< script src ='./output/app.js '> </ script >
</ body >
</ html >
Run the server
Do your happy dance!
My first PureScript app π
Install Pux
Imports
import Prelude hiding (div )
import Control.Monad.Eff (Eff )
import Pux (CoreEffects , EffModel , start )
import Pux.DOM.Events (onClick )
import Pux.DOM.HTML (HTML )
import Pux.Renderer.React (renderToDOM )
import Text.Smolder.HTML (button , div , span )
import Text.Smolder.Markup (text , (#!) )
User Actions
data Event = Increment | Decrement
State
Update
foldp :: β fx . Event -> State -> EffModel State Event fx
foldp Increment n = { state: n + 1 , effects: [] }
foldp Decrement n = { state: n - 1 , effects: [] }
View
view :: State -> HTML Event
view count =
div do
button #! onClick (const Increment ) $ text " Increment"
span $ text (show count)
button #! onClick (const Decrement ) $ text " Decrement"
Main
main :: β fx . Eff (CoreEffects fx ) Unit
main = do
app <- start
{ initialState: 0
, view
, foldp
, inputs: []
}
renderToDOM " #app" app. markup app. input
Mount App and Add React
< body >
< div id ="app "> </ div >
< script src ="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js "> </ script >
< script src ="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js "> </ script >
< script src ='./output/app.js '> </ script >
</ body >
Bundle and Serve
Do your happy dance!
My first PureScript app that does something πΊ π
Install the aff module
Import modules
import Control.Monad.Aff.Console (CONSOLE , log )
import Data.Maybe (Maybe (.. )) -- Part of Prelude
Define App Effects
type AppEffects = ( console :: CONSOLE )
Log state to console
foldp :: β fx . Event -> State -> EffModel State Event AppEffects -- π
foldp Increment n = { state: n + 1 , effects: [
do
log $ " Current State: " <> (show $ n + 1 )
pure Nothing
]}
foldp Decrement n = { state: n - 1 , effects: [
do
log $ " Current State: " <> (show $ n - 1 )
pure Nothing
]}
Update Main
main :: β fx . Eff (CoreEffects AppEffects ) Unit -- π
main = do
app <- start
{ initialState: 0
, view
, foldp
, inputs: []
}
renderToDOM " #app" app. markup app. input
Run server
Do your happy dance!
My first PureScript side-effect πΊ
Install necessary modules
psc-package install argonaut-codecs affjax
Import modules
import Control.Monad.Aff (attempt )
import Data.Argonaut.Decode (decodeJson , (.?) )
import Data.Argonaut.Decode.Class (class DecodeJson )
import Data.Either (Either (Left , Right ), either )
import Data.Newtype (class Newtype , un )
import Network.HTTP.Affjax (AJAX , get )
import Text.Smolder.HTML (button , div , img )
import Text.Smolder.HTML.Attributes (src )
import Text.Smolder.Markup (text , (#!) , (!) )
Define effects
type AppEffects = ( console :: CONSOLE , ajax :: AJAX )
Define user actions
data Event = RequestGiphy | ReceiveGiphy (Either String Url )
Define a newtype (for decoding)
newtype Url = Url String
derive instance newtypeUrl :: Newtype Url _
unwrap :: Url -> String
unwrap = un Url
Define the state
Decoder
instance decodeJsonUrl :: DecodeJson Url where
decodeJson json = do
obj <- decodeJson json
info <- obj .? " data"
imgUrl <- info .? " image_original_url"
pure $ Url imgUrl
Update
foldp :: β fx . Event -> State -> EffModel State Event AppEffects
foldp RequestGiphy state = { state: state, effects: [
do
result <- attempt $ get " https://api.giphy.com/v1/gifs/random?api_key=670526ba3bda46629f097f67890105ed&tag=&rating=G"
let decode res = decodeJson res. response :: Either String Url
let url = either (Left <<< show ) decode result
pure $ Just $ ReceiveGiphy url
]}
foldp (ReceiveGiphy (Left _)) state = { state: state, effects: [ log " Error" *> pure Nothing ] }
foldp (ReceiveGiphy (Right url)) state = { state: url, effects: [ log " ReceivedGiphy" *> pure Nothing ]}
View
view url =
div do
button #! onClick (const RequestGiphy ) $ text " Get Random Giphy"
img ! src (unwrap url)
Main
main :: β fx . Eff (CoreEffects AppEffects ) Unit
main = do
app <- start
{ initialState: Url " " -- π
, view
, foldp
, inputs: []
}
renderToDOM " #app" app. markup app. input
Run server
Do your happy dance!
My first PureScript HTTP request πΊ π
Part 6: Make request from user input
Update Imports
import Pux.DOM.Events (onClick , onChange , DOMEvent , targetValue )
import Text.Smolder.HTML (button , div , img , input )
import Text.Smolder.HTML.Attributes (src , type' , value )
Update state
type State =
{ url :: Url
, input :: String
}
Update
foldp :: β fx . Event -> State -> EffModel State Event AppEffects
foldp RequestGiphy state = { state: state, effects: [
do
result <- attempt $ get $ " https://api.giphy.com/v1/gifs/random?api_key=670526ba3bda46629f097f67890105ed&tag=" <> state. input <> " &rating=G"
let decode res = decodeJson res. response :: Either String Url
let url = either (Left <<< show ) decode result
pure $ Just $ ReceiveGiphy url
]}
foldp (ReceiveGiphy (Left _)) state = { state: state, effects: [ log " Error" *> pure Nothing ] }
foldp (ReceiveGiphy (Right url)) state = { state: state { url = url }, effects: [ log " ReceivedGiphy" *> pure Nothing ]}
foldp (UserInput ev) state = { state: state { input = targetValue ev }, effects: [] }
View
view state =
div do
input ! type' " text" #! onChange UserInput ! value state. input
button #! onClick (const RequestGiphy ) $ text " Get Random Giphy"
img ! src (unwrap state. url)
Main
main :: β fx . Eff (CoreEffects AppEffects ) Unit
main = do
app <- start
{ initialState: { input: " " , url: Url " " } -- π
, view
, foldp
, inputs: []
}
renderToDOM " #app" app. markup app. input
Run server
Do your happy dance!
My first PureScript Giphy App π