$30 off During Our Annual Pro Sale. View Details »

RowList Fun with Purescript

Justin Woo
September 01, 2017

RowList Fun with Purescript

A small talk on RowList and some type-level programming in Purescript given at Small FP Conf 2017 in Tampere.

Reddit thread: https://www.reddit.com/r/purescript/comments/6xs5f2/rowlist_fun_with_purescript_slides_from_small_fp/

Justin Woo

September 01, 2017
Tweet

More Decks by Justin Woo

Other Decks in Programming

Transcript

  1. RowList Fun with
    PureScript
    Justin Woo
    Small FP Conf 2017

    View Slide

  2. What is PureScript?
    ● Pure, Strict, Functional
    ● Higher Kinded Types
    ● Type classes with functional dependencies
    ● Tooling with purescript-ide server + client
    ● Docs for packages on Pursuit
    ● Easy-to-use build tool in Pulp
    ● Typed holes with type-directed search
    ● No runtime -- compiles to real JS
    ● Row types
    ● ...and more!

    View Slide

  3. What are Row types?
    ● An unordered collection of fields
    ○ Key is Symbol (a type-level string kind)
    ○ Value is of the kind provided to the row
    data Record :: # Type -> Type
    -- takes row of Type to define a Type
    type Person =
    { name :: String, age :: Number }
    type Person =
    Record (name :: String, age :: Number)
    ● Eff works this way!
    kind Effect
    data HTTP :: Effect
    data Eff :: # Effect -> Type -> Type
    main :: Eff ( http :: HTTP ) Unit

    View Slide

  4. Collection? How about as a List?
    ● What if we could use these rows as lists of fields? Wouldn’t that be fun?
    kind RowList
    data Nil :: RowList
    data Cons :: Symbol -> Type -> RowList -> RowList
    type PersonRow = (name :: String, age :: Number)
    type PersonRowList = (Cons "name" String (Cons "age" Number Nil))

    View Slide

  5. Type classes: “type-level case statements”
    ● How do you match and work with things on the type level? Type classes!
    ○ Using instances for each branch
    ● Simple example: getting keys from a record
    class Keys (xs :: RowList) where
    keysImpl :: RLProxy xs -> List String
    instance nilKeys :: Keys Nil where
    keysImpl _ = mempty
    -- Phantom types reminder
    data Maybe a = Nothing | Just a
    data Proxy a = Proxy
    data RLProxy (xs :: RowList) = RLProxy

    View Slide

  6. Cons instance of class Keys
    1. Pattern match on the RowList
    2. Reflect the Symbol to a string value
    3. Get the rest by calling keysImpl on the tail
    4. Cons this string onto the rest of the keys
    That’s it!
    instance consKeys ::
    ( IsSymbol name
    , Keys tail
    ) => Keys (Cons name ty tail) where
    keysImpl _ = first : rest
    where
    first = reflectSymbol (SProxy :: SProxy name)
    rest = keysImpl (RLProxy :: RLProxy tail)

    View Slide

  7. Exposing our method in a reasonable way
    ● We wrote a class for RowList, but this needs to work for row types from Records
    ● RowToList allows us to convert row to RowList for exactly this!
    keys :: forall row rl. RowToList row rl => Keys rl => Record row -> List String
    keys _ = keysImpl (RLProxy :: RLProxy rl)
    ● Since we have everything from the type level, the record ends up being a glorified Proxy

    View Slide

  8. Keys in action
    Usage:
    main =
    traverse_ print $ keys { a: 1, b: 2 }
    Output:
    "a"
    "b"

    View Slide

  9. ● Purescript-Simple-JSON: automatically parse record type aliases without any setup
    ○ Also writes JSON safely (e.g. no function stringifying)
    ● Purescript-Kancho: restrict Purescript types to Elm port types and generate Elm types
    ● Purescript-OhYes: restrict Purescript types to be Typescript-safe and generate type definitions, using
    polymorphic variants through Purescript-Variant to support discriminant-field union types in
    Typescript
    ● Purescript-ChocoPie: a Cycle.js-like library that exposes record-based APIs for creating cycles of Events
    from Purescript-Behaviors
    ● Purescript-IndexedDB-Safe by Antti Holvikari: type-safe wrappers for IndexedDB
    ● … and more!
    Other applications of RowList

    View Slide

  10. “Will I need to do this if I [use / start using]
    Purescript?”
    ● Writing type-level code using RowList?
    ○ Not really, but sometimes
    ○ And you will learn these from usage
    ● Defining your own type classes and working with them?
    ○ Not necessarily, but sometimes
    ○ And you will learn these from usage
    ● Understanding how to use constraints and throw them around?
    ○ Yes and no
    ○ You will learn these from usage
    ○ You can always start with the most concrete types and use more general ones over time
    ■ e.g. Monoid mempty vs []

    View Slide

  11. Thanks!
    Ask me Purescript questions on Twitter: @jusrin00
    Map/Zip/Keys examples on github.com/justinwoo/purescript-map-record
    IRC: #purescript on freenode
    Slack: #purescript on Functional Programming Slack
    Reddit: /r/purescript

    View Slide