Skip to content

Instantly share code, notes, and snippets.

@choonkeat
Last active August 12, 2020 17:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save choonkeat/fff1cdc27442db08f90dbc7071f75a32 to your computer and use it in GitHub Desktop.
Save choonkeat/fff1cdc27442db08f90dbc7071f75a32 to your computer and use it in GitHub Desktop.

Scenario: Given a cookie string (which may be absent), parse and return a User record/struct

Often we'd write functions where arguments are "nullable", aka *string in Go, aka a Maybe in Elm

-- function `userFromCookie` with parameter type `Maybe String` return type `User`
userFromCookie1 : Maybe String -> User
userFromCookie1 maybeString =
    case maybeString of
        Nothing ->
            Anonymous

        Just s ->
            ...

It's beneficial to write functions that simply work with "solid" values (the "not nullable" variant). One benefit is that my function bodies end up simpler

userFromCookie2 : String -> User
userFromCookie2 s =
    ...

"But if the argument value can indeed by absent, aka null or Nothing, we can't avoid managing that, right?" Yes, the tradeoff is that the call sites of those functions become more involved

  currentUser =
-     userFromCookie1 maybeCookieString
+     Maybe.withDefault Anonymous (Maybe.map userFromCookie2 maybeCookieString)

Once you get used to seeing map, withDefault, andThen and notice the same patterns occur in other structures like Result, RemoteData, List, ...

call sites of those functions become more involved

you'll see there's a structure to this code increase (it isn't adhoc) and realise that when functions work with "solid" values parameters, the hit rate of reusing them goes up steeply -- the same function can just be slot into various context verbatim.

let
    userResult =
        Result.map userFromCookie2 stringReadFromIO
in
case userResult of
    Err err ->
        -- render IO error with variable `err`

    Ok user ->
        -- render `User` with variable `user`
cookieStrings : List String
cookieStrings =
    [ string1, string2, string3 ]

userList : List User
userList =
    List.map userFromCookie2 cookieStrings

Whereas functions written in our earlier style, userFromCookie : Maybe String -> User, would be awkward to reuse

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment