2010-01-31 1 views
36

я следующее GHCI:Haskell Неоднозначные происшествия - как этого избежать?

:m + Data.Map 
let map = fromList [(1, 2)] 
lookup 1 map 

GHCI знает, что карта является (Map Integer Integer). Итак, почему он требует двусмысленности между Prelude.lookup и Data.Map.lookup, когда тип ясен, и я могу избежать?

<interactive>:1:0: 
    Ambiguous occurrence `lookup' 
    It could refer to either `Prelude.lookup', imported from Prelude 
          or `Data.Map.lookup', imported from Data.Map 

> :t map 
map :: Map Integer Integer 
> :t Prelude.lookup 
Prelude.lookup :: (Eq a) => a -> [(a, b)] -> Maybe b 
> :t Data.Map.lookup 
Data.Map.lookup :: (Ord k) => k -> Map k a -> Maybe a 

ответ

46

типы явно отличаются, но Haskell не позволяет одноранговой перегрузку имен, так что вы можете выбрать только один lookup использоваться без префикса.

Типичное решение для импорта Data.Map квалифицированное:

> import qualified Data.Map as Map 

Тогда вы можете сказать

> lookup 1 [(1,2), (3,4)] 
Just 2 
> Map.lookup 1 Map.empty 
Nothing 

Обычно библиотеки Haskell либо избежать повторного использования имен из Prelude, либо повторно использовать целая куча их. Data.Map является одним из вторых, и авторы ожидают, что вы его импортируете.

[Редактировать включить комментарий ephemient в]

Если вы хотите использовать Data.Map.lookup без префикса, вы должны скрывать Prelude.lookup, поскольку он неявно импортирован иначе:

import Prelude hiding (lookup) 
import Data.Map (lookup) 

Это немного странно, но может полезно, если вы используете Data.Map.lookup целую кучу, а ваши структуры данных - все карты, а не алисты.

18

На несколько более общем плане, это то, что меня смутило в первом - так, позвольте мне повторить и подчеркнуть то, Натан Сандерс сказал:

Haskell не позволяет одноранговой перегрузку имен

Это правда по умолчанию, но сначала кажется неожиданно неочевидным. Haskell позволяет два стиля polymorphic functions:

  • Параметрический полиморфизм, что позволяет функции работать на любых типах в структурно идентичных, абстрактно
  • Ad-Hoc полиморфизм, которая позволяет функции работать на любом из определенного набора типов в структурно отличном, но, мы надеемся, семантически идентичном способе

Параметрический полиморфизм является стандартным (и предпочтительным заданием выбора) подхода в Haskell a родственные языки; ad-hoc-полиморфизм является стандартом на большинстве других языков, идя по именам, таким как «перегрузка функций», и часто реализуется на практике, написав несколько функций с тем же именем.

Ad-Hoc полиморфизм включена в Haskell по типа классов, которые требуют класса должны быть определены со всеми связанными с ним одноранговых полиморфных функций и примеры должны быть явно объявлены для типов используемых разрешения перегрузки.Функции, определенные вне декларации экземпляра, никогда не являются ad-hoc полиморфными, даже если их типы достаточно различны, что ссылка будет недвусмысленной.

Таким образом, если в разных модулях определены несколько функций нестандартного типа с одинаковыми именами, при импорте обоих модулей неквалифицировано приведет к ошибкам, если вы попытаетесь использовать любую функцию. Комбинации Data.List, Data.Map и Data.Set являются особенно вопиющими в этом отношении, и поскольку части Data.List экспортируются Прелюдией, стандартная практика (как говорит Натан Сандерс) всегда импортировать других квалифицированных специалистов.

+0

Это тот ответ, который я искал, +1. Но у меня есть вопрос. Почему тогда нет «контейнера» для всех этих «Data.List», «Data.Set» и т. Д.? Или, если есть (и если я правильно понимаю, это класс «Functor»), то почему определение его экземпляров для типов контейнеров не является повсеместным в библиотеках? – ulidtko

+0

@ulidtko: Короткий ответ «потому что это сложнее, чем кажется», и длинный ответ не вписывается в комментарий. Есть много осложнений, связанных с тем, какие контейнеры поддерживают какие операции и ограничения на типы элементов, & c. Поиск информации о расширении 'TypeFamilies' - API-интерфейсы контейнера являются для него мотивирующим примером. –

+3

@ulidtko Это может быть интересно для вас: http://hackage.haskell.org/packages/archive/classy-prelude/0.4.1/doc/html/ClassyPrelude.html –

Смежные вопросы