Skip to content

Instantly share code, notes, and snippets.

View Gryff's full-sized avatar

Liam Griffin-Jowett Gryff

View GitHub Profile
@Gryff
Gryff / functorsAndApplicativeFunctors.js
Created February 23, 2017 16:20
Functors, Applicative Functors in Javascript
// functors are computational contexts around values
// or, you could say they are boxes around values
// one instance of a functor is Maybe
// say you have a function that might return a value or undefined
function possiblyAValue() {
return Math.floor((Math.random() * 2)) === 0 ? undefined : { hey: { iAm: 'A value!' } }
}
-- our bank functions
deposit :: Int -> State [Transaction] ()
deposit amount = modify (\transactions -> transactions ++ [Deposit amount])
withdraw :: Int -> State [Transaction] ()
withdraw amount = modify (\transactions -> transactions ++ [Withdrawal amount])
getStatement :: State [Transaction] String
getStatement = gets generateStatement -- the details of generateStatement are out of scope of this post
printStatement :: State [Transaction] ()
printStatement = do
transactions <- get
let statement = generateStatement transactions
putStr statement
printStatement :: StateT [Transaction] IO ()
printStatement = do
  transactions <- get
  let statement = generateStatement transactions
  lift (putStr statement)
lift :: m a -> t m a
-- more concretely for our use case
lift :: IO () -> StateT [Transaction] IO ()
main = do
  runStateT useMyBank []
  pure () - we need to return IO () for main
useMyBank :: StateT [Transaction] IO ()
useMyBank = do
  deposit 200
  withdraw 100
  printStatement
it "sends statement to the aether" $ do
  runStateT printStatement [Deposit 100] `shouldBe` … -- the return type is IO ((), [Transaction]), statement is gone
printStatement :: StateT [Transaction] IO ()
printStatement = innerPrintStatement putStr
innerPrintStatement :: Monad m => (String -> m ()) -> StateT [Transaction] m ()
innerPrintStatement printer = do
  transactions <- get
  let statement = generateStatement transactions
  lift (printer statement)
testPrintStatement :: StateT [Transaction] (Writer String) ()
testPrintStatement = innerPrintStatement (\statement -> tell statement)
it "prints a statement" $ do
  -- evalStateT works just like evalState, except it will return us a `Writer String ()` instead of just `()`
  -- we can then use execWriter to get the String from Writer String ()
  execWriter (evalStateT testPrintStatement [Deposit 100, Withdrawal 50]) `shouldBe` "Deposited 100\nWithdrew 50"
areTheseEqual :: a -> a -> Bool
areTheseEqual a b = a == b