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