Haskell不明确的事件 - 如何避免?

me2*_*me2 42 haskell map

我在GHCI做以下事情:

:m + Data.Map
let map = fromList [(1, 2)]
lookup 1 map
Run Code Online (Sandbox Code Playgroud)

GHCI知道map是(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
Run Code Online (Sandbox Code Playgroud)

Nat*_*ers 53

类型明显不同,但Haskell不允许临时重载名称,因此您只能选择一个lookup没有前缀的方法.

典型的解决方案是导入Data.Map合格的:

> import qualified Data.Map as Map
Run Code Online (Sandbox Code Playgroud)

然后你可以说

> lookup 1 [(1,2), (3,4)]
Just 2
> Map.lookup 1 Map.empty
Nothing
Run Code Online (Sandbox Code Playgroud)

通常,Haskell库要么避免重复使用Prelude中的名称,要么重新使用它们中的一大堆.Data.Map是第二个,作者希望你导入它合格.

[编辑包括ephemient的评论]

如果你想在Data.Map.lookup没有前缀的情况下使用,你必须隐藏,Prelude.lookup因为它是隐式导入的,否则:

import Prelude hiding (lookup) 
import Data.Map (lookup)
Run Code Online (Sandbox Code Playgroud)

Data.Map.lookup有点奇怪,但是如果你使用一大堆而你的数据结构都是地图,那么可能会很有用.


C. *_*ann 23

稍微更一般地说,这首先使我感到困惑 - 所以,让我重申并强调内森桑德斯所说的话:

Haskell不允许临时重载名称

默认情况下这是正确的,但最初看起来非常明显.Haskell允许两种样式的多态函数:

  • 参数多态,允许函数以结构相同的抽象方式对任意类型进行操作
  • Ad-hoc多态,允许函数以结构上不同但希望语义相同的方式对任何定义的类型进行操作

参数多态性是Haskell和相关语言中的标准(并且是首选的选择)方法; ad-hoc多态性是大多数其他语言的标准,通过诸如"函数重载"之类的名称,并且通常通过编写具有相同名称的多个函数来实现.

在Haskell中通过类型类启用Ad-hoc多态,这需要使用所有关联的ad-hoc多态函数定义类,并为重载解析使用的类型显式声明实例.在实例声明之外定义的函数永远不是ad-hoc多态的,即使它们的类型足够明显,引用也是明确的.

因此,当在不同模块中定义多个具有相同名称的非类型类函数时,如果尝试使用任一函数,则导入两个不合格的模块将导致错误.的组合Data.List,Data.Map以及Data.Set在这方面特别严重,而且由于部分Data.List由序曲输出,标准的做法是(弥敦道桑德斯说)总是导入其他合格.

  • @ulidtko这可能对您有意思:http://hackage.haskell.org/packages/archive/classy-prelude/0.4.1/doc/html/ClassyPrelude.html (3认同)