On Friday, February 10, 2017 at 3:26:38 PM UTC, Joey Eremondi wrote:
>
> So, Elm lets you do a forall over the rest of a record.
>
> {a | x : Int} -> Int says this function accepts any record that has an x 
> Int field.
>

I am trying to build a model with states, such that fields are only 
available that are actually needed in the relevant state. The model is like 
this:

type alias WithPosition a =
    { a | rect : Rectangle }


type alias WithValue a =
    { a | value : String }


type State
    = Hidden
    | Aware (WithPosition {})
    | Active (WithPosition (WithValue {}))
    | Inactive (WithPosition (WithValue {}))
 

It can be convenient to have functions to work on fields in the model, only 
when the state is such that those fields are available. Here is one such 
function:

mapWhenWithPosition : (WithPosition {} -> a) -> State -> Maybe a
mapWhenWithPosition func state =
    case state of
        Aware { rect } ->
            Just <| func { rect = rect }

        Active { rect } ->
            Just <| func { rect = rect }

        Inactive { rect } ->
            Just <| func { rect = rect }

        _ ->
            Nothing

So when in a state that is 'positioned' this function lets me apply a 
function to the position and return the result in a Just, otherwise 
Nothing. Makes it easy to have a UI component that will only appear in 
certain states, for example.

What I don't understand is why this fails to type check:

mapWhenWithPosition : (WithPosition b -> a) -> State -> Maybe a
mapWhenWithPosition func state =
    case state of
        Aware rect ->
105:            Just <| func rect

        Active rect ->
            Just <| func rect

        Inactive rect ->
            Just <| func rect

        _ ->
            Nothing

Complains that:

    The argument to function `func` is causing a mismatch.

    105|                     func rect
                              ^^^^
    Function `func` is expecting the argument to be:

        WithPosition b

    But it is:

        WithPosition {}

I marked in which line is 105 above. The function WithPosition b -> a is 
general enough to handle a WithPosition {}, but I seem to be only able to 
use it where it fully matches.

This would seem to make extensible records a lot less useful than they 
could be. Is this one of those cases where an existential qualifier would 
be needed to specify the type of the function? Or is this in fact a case 
that could be typed in Elm without problem and that the type checker should 
accept?

Or perhaps there is some other way of writing what I want?

Inactive { rect } ->
            Just <| func { rect = rect }

Isn't too bad, but it gets a lot worse when there are lots more fields and 
you are having to deconstruct then reconstruct the same record:

SomeStatate { field1, field2, ..., fieldn } ->
            Just <| func { field1 = field1, field2 = field2, ..., fieldn = 
fieldn }


-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to