Dealing with ambiguous occurrence in Haskell

Viewed 250

I'm importing both Data.Text and Data.List and their respective find functions collapse.

import Data.Text
import Data.List

my_list = [4, 2, 4, 5, 6, 2, 6]
find (\a -> a == 5) my_list

The above code leads to the following error

    Ambiguous occurrence ‘find’
    It could refer to
       either ‘Data.Text.find’, imported from ‘Data.Text’
           or ‘Data.List.find’,
              imported from ‘Data.List’
              (and originally defined in ‘Data.Foldable’)

Is the only solution to use Data.List.find (\a -> a == 5) my_list here, or qualified imports?

What strikes me is that

Data.List.find (\a -> a == 5) my_list
--> Just 5

Data.Text.find (\a -> a == 5) my_list
--> error: Couldn't match expected type ‘Text’ with actual type ‘[Integer]’

From the find function signatures, the compiler is apparently able to understand that Data.Text.find doesn't work with [Integer]. Can't he use this information to decide on which instance of find to use and, in this case, automatically use find from Data.List ?

1 Answers

Is the only solution to use Data.List.find (\a -> a == 5) my_list here, or qualified imports?

As far as I know, yes, there are no other solutions.

The compiler won't try to type-check both options and use the one which makes your code compile. In the most general case, that could lead to an exponential blow-up. Consider, e.g.,

foo a1 a2 .... aN

where each one of a1 .. aN are imported from two distinct modules. Trying which combination type-checks would in principle require to test 2^N combinations.

Further, there's always the chance that the programmer meant to use an identifier from a module, but they made a mistake and the code does not type-check. In this case, the same identifier from the other module might instead type-check, making the code compile but producing the wrong result. (This is a rather contrived example, I know.)


Note that, if in your importing module you only need to use one of the two finds you can hide the other:

import Data.Text hiding (find)
import Data.List

Alternatively, you can provide explicit disjoint import lists:

import Data.Text (pack)
import Data.List (find, zip)

If you need both finds, you can provide a shorter name for the module

import Data.Text as T
import Data.List as L

as then disambiguate using L.find. You won't need the shorter module name except for the doubly imported identifiers. If you use import qualified instead you will need to specify the module name for all imported identifiers.

Related