pha*_*t0m 9 haskell types language-design
假设我要(+)在字符串上定义,而不是通过给出一个实例Num String.
为什么Haskell现在隐藏了Nums (+)功能?毕竟,我提供的功能:
(+) :: String -> String -> String
Run Code Online (Sandbox Code Playgroud)
可以通过Prelude的编译器来区分(+).为什么两个函数不能存在于同一名称空间中,而是具有不同的非重叠类型签名?
只要代码中没有调用函数,Haskell就会关心有一个ambiguitiy.然后,使用参数调用函数将确定类型,以便可以选择适当的实现.
当然,一旦存在实例Num String,实际上就会存在冲突,因为在那时Haskell无法根据参数类型决定选择哪个实现,如果实际调用了该函数.
在这种情况下,应该提出错误.
这不会允许函数重载而没有陷阱/模糊吗?
注意:我不是在谈论动态绑定.
sep*_*p2k 19
Haskell根本不支持函数重载(除了通过类型类).其中一个原因是函数重载不适用于类型推断.如果你有类似的代码f x y = x + y,怎么会哈斯克尔知道是否x和y是订购数量或字符串,即类型是否f应该f :: Num a => a -> a -> a还是f :: String -> String -> String?
PS:这与你的问题并不真正相关,但如果你假设一个开放的世界,那么类型并不是严格不重叠的,即在某个模块的某个地方可能有一个实例Num String,当导入时会破坏你的代码.所以Haskell根本不会根据给定类型没有给定类型类的实例做出任何决定.当然,即使没有涉及类型类,函数定义也会隐藏其他具有相同名称的函数定义,正如我所说:与您的问题不相关.
关于为什么必须在定义站点知道函数的类型而不是在调用站点推断它:首先,函数的调用站点可能在与函数定义不同的模块中(或者在多个模块中)不同的模块),所以如果我们必须查看调用站点以推断函数的类型,我们必须跨模块边界执行类型检查.那就是在对模块进行类型检查时,我们还必须完成导入该模块的所有模块,因此在最坏的情况下,每次更改单个模块时都必须重新编译所有模块.这将使编译过程变得非常复杂和变慢.更重要的是,它将使编译库成为不可能,因为库的本质是它们的函数将被编译器在编译库时无法访问的其他代码库使用.
只要没有调用该函数
在某些时候,当使用功能
不不不.在Haskell中你不会想到"之前"或"你做的那一刻......",而是一劳永逸地定义东西.这在变量的运行时行为中最为明显,但也转换为函数签名和类实例.这样,您不必对编译顺序进行所有繁琐的思考,并且从许多方面都是安全的,例如,由于程序中的一个微小变化,C++模板/重载经常会破坏.
另外,我不认为你完全理解Hindley-Milner的作品.
在调用函数之前,您知道参数的类型,它不需要知道.
好吧,你通常不知道参数的类型!它有时可以明确给出,但通常是从其他参数或返回类型推导出来的.例如,在
map (+3) [5,6,7]
Run Code Online (Sandbox Code Playgroud)
编译器不知道数字文字有什么类型,它只知道它们是数字.通过这种方式,您可以将结果评估为您喜欢的任何内容,并且允许您只能在其他语言中使用的内容,例如符号类型
> map (+3) [5,6,7] :: SymbolicNum
[SymbolicPlus 5 3, SymbolicPlus 6 3, SymbolicPlus 7 3]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1189 次 |
| 最近记录: |