Skip to content

Instantly share code, notes, and snippets.

@ajnsit
Last active March 26, 2019 08:54
Show Gist options
  • Save ajnsit/0f06e40d207843fe03681cac58fc9262 to your computer and use it in GitHub Desktop.
Save ajnsit/0f06e40d207843fe03681cac58fc9262 to your computer and use it in GitHub Desktop.
Syntactic Tricks for Purescript

Some Small Syntactic Tricks for Purescript

Pointfree

-- Given a simple 2 arg function
minus :: Int -> Int -> Int
minus x y = x - y

-- We can easily paramterise on the second argument
subtractFrom2 :: Int -> Int
subtractFrom2 = minus 2

-- The question is how do we parameterise the *first* argument?

-- Pointful way
subtract2 :: Int -> Int
subtract2 y = minus x 2

-- Pointfree using `flip`. Boring...
subtract2 :: Int -> Int
subtract2 = flip minus 2

-- Pointfree using `<@>`. Uses functor instance for functions. Cool!
-- <@> :: Functor f => f (a -> b) -> a -> f b
-- minus :: F (a -> b) === x -> (a -> b)
-- 2 :: a
-- minus <@> 2 :: F b === x -> b
subtract2 :: Int -> Int
subtract2 = minus <@> 2

Effectful function as the first argument

-- It's a common pattern to take a monadic function as first arg, and an object to operate on as the second arg
withName :: forall m a. (Name -> m a) -> Person -> m a
withName f p = f p.name

-- We take the function as the first arg because then it's easy to parameterise the object
printName :: Person -> Effect Unit
printName = withName \n -> putStrLn ("Name : " <> n)

-- And of course, we can also parameterise on the function with `<@>`
withJohn :: forall m a. (Name -> m a) -> m a
withJohn = withName <@> john

-- But when using the function fully saturated it looks ugly, especially when the function is large
validPerson :: PersonId -> Effect Bool
validPerson pid = do
  p <- getPerson pid
  withName (\name -> do
    let isTooShort = length name < 2
    isValidIdentifier <- validateIdentifier name
    pure $ not isTooShort && isValidIdentifier) p --- Ugly parens need closing, Plus this `p` is almost buried.

-- What we can do instead is use `#`
validPerson :: PersonId -> Effect Bool
validPerson pid = do
  p <- getPerson pid
  p # withName \name -> do
    let isTooShort = length name < 2
    isValidIdentifier <- validateIdentifier name
    pure $ not isTooShort && isValidIdentifier --- No ugly parens needed! No buried `p` argument.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment