我对 Haskell 还是很陌生(断断续续地学习它)。我想知道为什么 Haskell 没有文字Data.Map
构造函数语法,例如 Clojure 或 Ruby 中的 Map/Hash 构造函数语法。有原因吗?我认为由于 Haskell 确实有一个文字构造函数语法 for Data.List
,所以应该有一个 for Data.Map
。
这个问题根本不是批判的。我只想通过答案了解更多关于 Haskell 的信息。
与 Clojure 和 Ruby 不同,Haskell 的有限映射是作为库提供的。这需要权衡取舍:例如,正如您所注意到的,有限映射没有内置语法;然而,因为它是一个库,我们可以(并且确实)有许多替代实现,作为程序员,您可以选择最适合您使用的实现。
除了已经给出的答案(尽管是“历史事故”),我认为与在 Ruby 或类似事物Data.Map
中相比,在 Haskell中的使用还有一些话要说;Hash
其他语言中的类似地图的对象往往更多地用于一般的临时存储。
而在 Haskell 中,您data
可以立即做出定义,而在其他语言中创建类往往有点重量级,因此我们发现即使对于具有众所周知结构的数据,我们也只会使用一个Hash
或dict
或类似的。事实上,我们有一个直接的语法来做到这一点,这使得它成为一个更具吸引力的选择。
与 Lisp 相比:使用MAKE-HASH-TABLE
然后重复SETF
ing 它相对烦人(类似于 using Data.Map
),因此所有内容都被扔进嵌套列表中,因为它很方便。
同样,我很高兴存储数据最方便的选择是创建适合的新类型,然后Data.Map
在我实际构建映射或哈希表作为内在组件时留待。在某些情况下,我认为语法会很好(通常只适用于较小的一次性程序),但总的来说我不会错过它。
实际上我不确定为什么没有人在答案中指出它(只有 sam boosalis 的评论)但是OverloadedLists
你几乎可以得到Map
and的字面语法Set
:
{-# LANGUAGE OverloadedLists #-}
import Data.Map
import Data.Set
foo :: Map Int Int
foo = [(1,2)]
bar :: Set Int
bar = [1]
从那里开始,只需再迈出一步即可获得更好看的地图,例如:
a =: b = (a,b)
ages :: Map String Int
ages = [ "erik" =: 30
, "john" =: 45
, "peter" =: 21 ]
虽然我个人更喜欢显式而不是隐式,所以除非我正在构建一个 DSL,否则我仍然会坚持fromList
并且(foo, bar)
- Haskell 是关于大胜利而不是小胜利。
Haskell 对列表有特殊的语法,因为在惰性函数语言中,它们或多或少地取代了命令式语言中的循环控制结构。因此,它们比Map
宏伟计划中的重要得多。
另外,我知道你[1,2,3]
说的是“列表语法”,但我想补充一点,列表构造函数语法几乎可以在 haskell-98 中实现,因为类型构造函数在以 开头时可以是中缀:
,例如
data Pair = Int :-- Int
所以列表构造函数:
只是这个通用语法规则的一个小特例,它非常优雅。有些人错过了这一点。
Haskell 确实有一个 Map 构造函数,但它是“隐藏的”(就像面向对象范例中的私有方法一样)。鼓励您使用“公共”构造函数,例如empty、singleton或fromList。但是,如果您检查https://hackage.haskell.org/package/containers-0.4.0.0/docs/src/Data-Map.html上提供的代码,您会得到以下定义
data Map k a = Tip
| Bin {-# UNPACK #-} !Size !k a !(Map k a) !(Map k a)
您可以使用Tip和Bin构造函数,但不建议这样做。