Problem understanding Maybe

Back again, so thanks for all responses to this any previous questions. I’m grateful that there’s such a community out there so supportive of rank beginners.

I have spent the weekend trying and failing fully to grasp Maybe. The start point is this: I have a Model which contains a list of photos, one of which is the current one.

type alias Model =
{ photos : List Photo
, selectedPhoto : Maybe Photo
}

The photo list is initially empty, so the selectedPhoto has to be of type Maybe Photo and is initialised to Nothing. So far so good.

Photo is itself a record with, for the time being, only one attribute, its url; more precisely the last part of its file name (e.g. “1.jpeg”, “2.jpeg” …). I have made it a record because I’d like to add metadata associated with each photo at some stage (location, camera, lens, aperture, shutter speed etc.)

Type alias Photo =
{ url : String }

I can successfully read into model.photos a list of urls and set model.selectedPhoto:

update msg model =
case msg of
GotPhotos result -> – GotPhotos is the Msg passed to and returned by Http.get
case result of
Ok responseString ->
let
pictures : List Photo
pictures = List.map (\str-> { url = str }) (String.split “,” responseString)
selected : Maybe Photo
selected = List.head pictures
in
( { model | photos = pictures, selectedPhoto = selected }, Cmd.none )

            Err httpError ->
                ( { model | status = ErrorOnLoading "Server Error"}, Cmd.none )

Where I am utterly stuck is trying to recover the url from model.selectedPhoto so that I can concatenate it with a constant directory name (urlPrefix) to give the full path as the “scr” in an Element.image call. Everything I have tried just gives compiler errors that, although fulsome, aren’t helping me.

For example:

src = urlPrefix ++ model.selectedPhoto.url

gives the error:

The value at .selectedPhoto is a:

Maybe Photo

But I need a record with a url field!

I know that, but how do I get it!!!

I clearly don’t understand Maybe as well as I need and the tutorials all seem to deal with much simpler cases. Any help would be gratefully received …

As selectedPhoto is a Maybe. You have to handle the possibility of not having a selected photo.

So your view needs to do something like:

case model.selectedPhoto of
    Nothing ->
       text "No photo selected"
   Just photo ->
       img [ src (urlPrefix ++ photo.url) ] []

The phrase to look for will be “pattern matching” or even “destructuring” — to get values out of these types

I found this helpful https://gist.github.com/yang-wei/4f563fbf81ff843e8b1e but this might explain better https://elmprogramming.com/pattern-matching.html

Think about the Maybe as a closed box. Now you know that there might be a photo inside the box or it might be empty. If you want to turn a Maybe into some kind of Html, you will therefore have to deal with both cases (empty box and box containing photo).

There are two ways to handle this: pattern matching (what @Sebastian showed above) and using a default.

If you need to show a photo, you might have a “no photo” photo (the default). Then you can have viewPhoto (Maybe.withDefault noPhoto model.selectedPhoto).

In essence Maybe.withDefault is:

withDefault defaultValue maybe = 
    case maybe of 
        Nothing -> 
            defaultValue 
        Just contents -> 
            contents 

Most of the time you will use pattern matching. Sometimes however, if you have a sensible default, you can also use Maybe.withDefault

If you want to learn more about this way of thinking, you can take a look at Railway oriented programming: Error handling in functional languages. The presentation makes all this more visual. Maybe that would help.

Thanks, that works as you’d expect. I thiught I’d trued something along those lines, but there must have been other errors in my code that threw me.

Can I just (excuse the pun) confirm one point?

Am I right in thinking that in the “Just photo” (line 4), Just isn’t a function, but one of the legitimate values of the Maybe type? “photo” is a name we’re temporarily giving to whatever satisfies its (i.e. Maybe’s) type argument? It could as easily be “x” or “fred”, and must be a Photo (so we can say .url) because we declared earlier that .selectedPhoto was Maybe Photo?

Hopefully getting there …

Thanks, they do look useful; I’d never have found them myself.

1 Like

Exactly right.


PS: Discourse complains that my post must be more than 20 characters… so here’s extra materials :rofl:

If you’d like, you can practice the understanding with Result

e.g. if we somehow change to selectedPhoto : Result String Photo, then the pattern matching we’d use to pull out the values will be

case selectedPhoto of
        Ok p ->
                -- do things with Photo `p`

        Err reason ->
                -- do things with String `reason`

Some more resources if you want to explore the concept of Maybe in more depth:

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.