Error msg does not make sense

I am trying to use List.unique on a list of tuples of a custom type. The compiler returns an error stating:

This map call produces:

List ( Maybe a, Maybe a )

But unique needs the 1st argument to be:

List ( Maybe a, Maybe a )

The map call is building the list of tuples from a list of the custom type.

unique
     (List.map (\a -> ( List.head a, List.Extra.last a ))
            (List.filter (\a -> List.length a == 2) (subsequences myList ))

where myList : List MyType. Why is the compiler complaining if the map call delivers the exact type that unique expects?

I’m guessing you were doing something like this:

import List.Extra as LE

foo : List a -> List (Maybe a, Maybe a)
foo myList =
  LE.unique
     (List.map (\a -> ( List.head a, LE.last a ))
            (List.filter (\a -> List.length a == 2) (LE.subsequences myList )))

The error message is confusing, but I think your problem is that unique expects an argument of type List comparable, and Maybe a is NOT comparable, hence, neither is List (Maybe a, Maybe a).

“Only ints, floats, chars, strings, lists, and tuples are comparable.”

unique requires its list elements to be comparable, because it inserts them in a Set to get n logn performance. If you can live with n**2 performance, you can write your own unique that just uses == for comparison.

1 Like

Or, even better, since you know that you’re dealing with only subsequences of length 2 here, you know that List.head and List.Extra.Last are NEVER going to return Nothing, so if you know a default value that will never be used, you can return List (a, a) instead of List (Maybe a, Maybe a), and use unique as is.

Something like this:

uniqueTwoTuples : List comparable -> List (comparable, comparable)
uniqueTwoTuples myList =
  LE.unique <| lengthTwoSubsequences myList

lengthTwoSubsequences : List a -> List (a, a)
lengthTwoSubsequences list =
  LE.subsequences list
    |> List.filterMap 
         (\l ->
            case l of
                [a, b] -> Just (a, b)
                _ -> Nothing
         )

Thanks. It appears the last statement there should actually be “Only ints, floats, chars, strings, lists of comparable items, and tuples of comparable items are comparable.”

That would be more accurate. I was quoting from the compiler message when I tried to make a Dict (Maybe Int) Int in Ellie.

In rust I could do something like implement a comparable trait for my custom type. Is it possible to make a custom type comparable in elm or do you just have to implement things like unique from scratch?

comparable is wired in. Haskell also allows that kind of thing, but Elm does not.

1 Like

List.Extra.uniqueBy serves the purpose in this case.

1 Like

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