Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Annotation function with filter causing too generic error

Tags:

generics

elm

I am trying to create a generic function to be able to accept a Maybe List of any record with an id : Int as a field, to find if an id exists in that list. The return could be one of three states, the Found record, NotFound, and a Loading message (for when the list is Nothing).

The errors have led me to this code so far, but am now stuck and don't understand how to fix this from the the error help (including reading through the link). How can I get this to work, and why exactly does this not work?

import Html exposing (text)

type alias RecordWithID a =
  { a | id : Int }


type alias MyRecord =
  { id : Int
  , name : String
}

type Find a
  = Found (RecordWithID a)
  | NotFound
  | Loading


findById : Int -> Maybe (List (RecordWithID a)) -> Find (RecordWithID a)
findById id maybeItems =
  case maybeItems of
    Just items ->
      let
        head = List.head <| List.filter (\x -> x.id == id) items
      in
        case head of
          Just item ->
            Found item

          Nothing ->
            NotFound

    Nothing ->
      Loading


main = text <| toString <| findById 4 (Just [ MyRecord 4 "hi" ])

Edit

The error:

-- TYPE MISMATCH ---------------------------------------------------------------

The type annotation for `findById` does not match its definition.

17| findById : Int -> Maybe (List (RecordWithID a)) -> Find (RecordWithID a)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The type annotation is saying:

    Int -> Maybe (List { b | id : Int }) -> Find { b | id : Int }

But I am inferring that the definition has this type:

    Int -> Maybe (List { b | id : Int }) -> Find b

Hint: A type annotation is too generic. You can probably just switch to the type
I inferred. These issues can be subtle though, so read more about it.
<https://github.com/elm-lang/elm-compiler/blob/0.17.0/hints/type-annotations.md>

I understand that the type of the record from the filter and head won't necessarily match a, but unsure on how to resolve the problem.

like image 559
gak Avatar asked Apr 16 '26 11:04

gak


1 Answers

This will compile successfully if you redefine Find a more generically:

type Find a
  = Found a
  | NotFound
  | Loading

Or, if you kept the definition of Find a as you originally coded it, you could annotate your function like this:

findById : Int -> Maybe (List (RecordWithID a)) -> Find a

Why does it work this way? I can only speculate. It feels a little like a typeclass constraint in Haskell (e.g. findById :: Record a => Int -> Maybe (List a) -> Find a, since a in the Elm version is only allowed to be constrained in the annotation once. I don't know whether this is true when it comes to the compiler but that's what it feels like. Again, that's just speculation.

like image 175
Chad Gilbert Avatar answered Apr 19 '26 04:04

Chad Gilbert



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!