Collections “哈斯克尔”;“收藏”;语言设计
为什么Haskell实现如此关注链表 例如,我知道数据。顺序更有效 与大多数列表操作(除了Collections “哈斯克尔”;“收藏”;语言设计,collections,haskell,language-design,Collections,Haskell,Language Design,为什么Haskell实现如此关注链表 例如,我知道数据。顺序更有效 与大多数列表操作(除了cons操作)一起使用,并且被大量使用; 然而,从句法上讲,它“几乎不受支持”。Haskell在函数抽象方面做了很多工作,例如Functor和Foldable类,但是它们的语法与默认列表的语法不兼容 如果在一个项目中,我想优化列表并用序列替换,或者如果我突然想要支持无限集合,并用列表替换序列,那么结果代码的更改是令人憎恶的 因此,我想我的疑惑可以具体化为以下问题: 为什么map的类型不等于(函子f)=>(a
cons
操作)一起使用,并且被大量使用;
然而,从句法上讲,它“几乎不受支持”。Haskell在函数抽象方面做了很多工作,例如Functor和Foldable类,但是它们的语法与默认列表的语法不兼容
如果在一个项目中,我想优化列表并用序列替换,或者如果我突然想要支持无限集合,并用列表替换序列,那么结果代码的更改是令人憎恶的
因此,我想我的疑惑可以具体化为以下问题:
map
的类型不等于(函子f)=>(a->b)->fa->fb
[]
和(:)
函数用于例如Data.Sequence中的类型我真的希望对此有一些解释,其中不包括“向后兼容性”或“它只是以这种方式增长”,但如果您认为没有,请让我知道。任何相关的语言扩展都是受欢迎的。我记得在某个地方读到,
map
默认用于列表,因为Haskell的新手如果犯了一个错误并看到了一个关于“functor”的复杂错误(他们对此一无所知),就会被推迟。因此,它们既有map
又有fmap
,而不仅仅是map
编辑:“某处”是《单子阅读器》第13期,第20页,脚注3:
3您可能会问,为什么我们需要单独的映射功能。为什么不干脆消除电流呢
仅列出映射函数,并将fmap重命名为映射?这是个好问题。这个
通常的观点是,当不正确地使用map时,刚学习Haskell的人会更容易理解
宁可看到关于列表的错误,也不要看到关于函子的错误
对于
(:)
,(我很确定这不会回答您的问题,但仍然是
我希望Haskell有更自由的函数名(mixfix!)。那么,列表构造函数(:
,[]
)的语法就不会那么神奇了;它至少允许我们隐藏列表类型并对自己的类型使用相同的标记
在列表类型和自定义序列类型之间迁移时,代码更改的数量将是最小的
关于map
,您比较幸运。您可以随时隐藏map,并将其设置为与fmap相同
import Prelude hiding(map)
map :: (Functor f) => (a -> b) -> f a -> f b
map = fmap
前奏曲很棒,但它不是Haskell最好的部分。在讨论原因之前,这里是问题的摘要以及您可以做些什么。构造函数[]
和(:)
是为列表保留的,无法重新定义。如果计划对多个数据类型使用同一代码,请定义或选择表示要支持的接口的类型类,并使用该类中的方法。
下面是一些既适用于列表又适用于序列的通用函数。我不知道(:)
,但您可以自己编写
fmap
而不是map
mempty
而不是[]
mappend
而不是(++)
如果您计划进行一次性数据类型替换,那么您可以为事物定义自己的名称,并在以后重新定义它们
-- For now, use lists
type List a = [a]
nil = []
cons x xs = x : xs
{- Switch to Seq in the future
-- type List a = Seq a
-- nil = empty
-- cons x xs = x <| xs
-}
——现在,使用列表
类型列表a=[a]
零=[]
cons x xs=x:xs
{-将来切换到Seq
--类型列表a=序列a
--零=空
--cons x xs=x一个吹毛求疵的数据。序列对于“列表操作”来说并不更有效,对于序列操作来说更有效。也就是说,Data.list中的许多函数实际上是序列操作。数据中的手指树。序列必须为cons做更多的工作(对于7.8版,ghc支持重载列表文本,比较。例如,给定适当的IsList
实例,您可以编写
['0' .. '9'] :: Set Char
[1 .. 10] :: Vector Int
[("default",0), (k1,v1)] :: Map String Int
['a' .. 'z'] :: Text
(引用自文档)。你所说的#2是什么意思?我可以想出两种合理的解释:(a)“为什么不能使现有的:
和[]
具有更多态的类型?”;(b)“为什么:
和[]
用于序曲。[
而不是数据.Sequence.Seq
?”。“它只是以这种方式增长”非常接近。@Antal:我的问题是(a),因为我想知道为什么这些函数/构造函数没有更多多态性。我的推理是,使用的实际数据类型可以从键入中推断出来(例如,使用列表a
或Seq a
)并且可以默认为列表。我怀疑您真正希望的是类似于GHC的东西,但应用于列表文字而不是字符串。不幸的是,这不仅不存在,而且似乎在我能找到的任何地方都没有建议过……这确实不是对我问题的回答,但更多的是澄清;我是aware我可以隐藏map
,并将其设置为等于fmap
。我的问题是,为什么我必须这样做?(上面已经给出了充分的答案。)关于Data.Sequence.empty
?或者Control.Monad.mempty
?他们应该这样做。虽然我同意这会增加Haskell已经很陡峭的学习曲线,但在学习了基础知识之后,是否应该有一种方法来平衡这一点?难道没有前奏曲吗将所有这些仅列出的函数修复为它们的通用对应项?@Pepijn:您不必使用前奏,只需放入import Prelude()
在您的代码中。对于我的大多数爱好/实验性Haskell编程,我使用了一个经过修改的前奏曲,除其他外,它将Headsink提到的列表函数替换为它们的通用等价物。对于更剧烈的更改(例如,为desugaringdo
符号替换Monad
),有