Usage of narrow type aliases in function's body

Hello,
I’m trying to decode init's flags into this type:

type alias SearchFilters a =
    { a
        | query : String
        , page : Int
        , pageSize : Int
    }

and my decoder looks like this:

initFlagsDecoder : Decode.Decoder (SearchFilters a)
initFlagsDecoder =
    Decode.succeed
        SearchFilters
        |> optional "query" Decode.string ""
        |> optional "page" Decode.int 0
        |> optional "pageSize" Decode.int 10

The problem here is that compiler says, that it cannot resolve type specified on 2nd line of initFlagsDecoder

Here is the compiler output:

I know that I could accomplish this task by creating non-narrowing type but that would create duplicities etc. Is there a way I can write it so that initFlagsDecoder would return { query : String, page : Int, size : Int } without creating new, dedicated type alias?

Thanks a lot!

1 Like

This compiles

initFlagsDecoder : Decode.Decoder (SearchFilters {})
initFlagsDecoder =
    Decode.succeed
        (\query page pageSize ->
            { query = query
            , page = page
            , pageSize = pageSize
            }
        )
        |> optional "query" Decode.string ""
        |> optional "page" Decode.int 0
        |> optional "pageSize" Decode.int 10
2 Likes

Didn’t thought of that… Thanks a lot :slight_smile:
Have a nice day

You can’t actually create an instance of this ‘type’ - the reason being that anything with a type variable in it (the a) needs that variable to be instantiated to form a ‘concrete’ type in order to fully know what it is that you are creating. As Sebastion points out, it works if you fill in the a as {}.

Also Elm does not create automatically a constructor for extensible records, like it does with non-extensible ones, so you need to create the construction function explicitly as in Sebastian’s example.

You mostly cannot create an instance of any type without filling in the type variable. So in Elm you cannot create say a List a and put anything into the list, you need to specify or let Elm infer what the a is before creating a list with things in it. However, you can create an empty list of type List a:

[]
[] : List a
[2]
[2] : List number – number is a type var, but a special case as its a type class.
[“hello”]
[“hello”] : List String – Concrete type of String, in order to have Strings in the list.

You can also have extra type args that are not filled in (shadow types):

> type Blah a b = Blah a
> Blah "hello"
Blah "hello" : Blah String b

a got a value so has to be concrete, but b is never used so can be left free.

2 Likes

Oh I see. That now makes a lot more sense… So I need constructor function but in that case it would be better/same to just create type alias without type params rigth? If so, could there be a way to use this new type alias JustSearchFilters = ... inside type alias SearchFilters a = ... so that I wouldn’t have to copy-paste its fields?

You can do this:

type alias JustSearchFilters =
    SearchFilters {}

Which will give you the right type alias - but unfortunately Elm does not generate the constructor when you define a record this way.

Ok. seems like its heplful mainly for function’s input params not for returning/creating them.
Thanks for the help guys! :slightly_smiling_face:

Yes it mainly is for that, although note it is useful for return values too, not just inputs:

somefun : { a | fieldOfInterest : String } -> { a | fieldOfInterest : String }

Works over any record type with the fieldOfInterest, and can return those records too, even though it only knows about part of the record.

Some stuff about this in here:

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