Scala 2.8收藏库是否是“历史上最长的自杀记录”的案例?[关闭]


873

我刚刚开始研究即将在2.8版本中发布的Scala集合库的重新实现。那些从2.7开始熟悉该库的人会注意到,从使用角度来看,该库变化很小。例如...

> List("Paris", "London").map(_.length)
res0: List[Int] List(5, 6)

...在任何一个版本中都可以使用。该库非常有用:实际上,它很棒。但是,那些以前不熟悉Scala并四处摸索以了解该语言的人现在必须理解方法签名,例如:

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That

对于这样简单的功能,这是一个令人生畏的签名,我发现自己很难理解。并不是说我认为Scala可能成为下一个Java(或/ C / C ++ / C#)的原因-我不相信它的创建者将其瞄准该市场-但我认为Scala成为/肯定是可行的下一个Ruby或Python(即获得大量商业用户)

  • 这会让人们不去斯卡拉吗?
  • 这是否会使Scala在商业世界中成为坏名声,因为只有专注的博士生才能理解这种学术玩法?被CTO S和软件的负责人会得到吓跑了?
  • 重新设计图书馆是明智的想法吗?
  • 如果您正在商业上使用Scala,您是否对此感到担心?您打算立即采用2.8还是等待观察会发生什么?

史蒂夫·耶格Steve Yegge)曾经攻击Scala(在我看来是错误的),因为他认为Scala的字体系统过于复杂。我担心有人会在野外使用此API 散布FUD(类似于Josh Bloch害怕JCP不会在Java中添加闭包)。

注意 - 我应该清楚一点,尽管我相信约书亚·布洛赫Joshua Bloch)在拒绝BGGA封闭提案方面具有影响力,但除了他诚实地认为该提案代表错误之外,我没有将这归因于其他任何事情。


尽管我的妻子和同事一直在告诉我什么,但我不认为我是个白痴:我在牛津大学获得了很好的数学学位,并且我从事商业编程已有近12年的时间,并且在Scala从事商业编程大约一年(也是商业上)。

请注意,煽动性的标题是对1980年代初期英国政党宣言的引用。这个问题是主观的,但这是一个真实的问题,我已将其定为CW,我希望对此事发表一些意见。


10
fud只代表恐惧,不确定性和怀疑-我认为我很清楚地表达了乔什·布洛赫(Josh Bloch)的讲话的语气,我也恰好同意这是有充分理由和理由的。我不想暗示-ve的含义
oxbow_lakes


7
我喜欢Scala的地方在于,您不必了解它的复杂类型系统即可执行简单而优雅的事情。它的语法可能令人生畏,但是可以向您保证,没有“魔术”,例如,魔术是语言的一部分,这是一种非常勇敢和聪明的方法,我认为,您拥有一种可以创建新的DSL和新的mini的语言。语言本身,是的,用错了手Scala可以很好地补充您的意大利晚餐,但是一旦您习惯了它,它就是一种了不起的语言
Eran Medan 2012年

87
当这个问题导致@MartinOdersky重新评估Scala的可用性并使其文档系统隐藏类型系统的详细信息时,怎么可能是“没有建设性的”?更不用说富有启发性的讨论了?
Jerry101

14
确实,SO只是出于技术上正确格式的考虑。如果您有一些精致,有趣和深远的东西,请找别的地方。官僚主义心态万岁。
2015年

Answers:


892

我希望这不是“遗书”,但我可以理解你的意思。您同时发现了Scala的强项和问题:它的可扩展性。这使我们可以在库中实现大多数主要功能。在其他一些语言中,将内置类似mapcollect将要构建的序列,并且没有人必须看到编译器必须经历的所有过程才能使它们顺利运行。在Scala中,所有内容都在一个库中,因此是公开的。

实际上map,它的复杂类型所支持的功能相当先进。考虑一下:

scala> import collection.immutable.BitSet
import collection.immutable.BitSet

scala> val bits = BitSet(1, 2, 3)
bits: scala.collection.immutable.BitSet = BitSet(1, 2, 3)

scala> val shifted = bits map { _ + 1 }
shifted: scala.collection.immutable.BitSet = BitSet(2, 3, 4)

scala> val displayed = bits map { _.toString + "!" }
displayed: scala.collection.immutable.Set[java.lang.String] = Set(1!, 2!, 3!)

看看如何始终获得最佳类型?如果将Ints 映射到Ints BitSet,则将再次得到a ,但是如果将Ints 映射到Strings,则将得到一个general Set。映射结果的静态类型和运行时表示形式均取决于传递给它的函数的结果类型。即使集合为空,此方法也有效,因此永远不会应用该功能!据我所知,没有其他具有相同功能的收集框架。然而,从用户的角度来看,这就是应该如何工作的方式。

我们面临的问题是,所有导致这种情况发生的聪明技术都会渗入类型签名中,这些签名变得很大而令人恐惧。但也许默认情况下不应该向用户显示的完整类型签名map?如果她抬起头来map,情况如何BitSet

map(f: Int => Int): BitSet     (click here for more general type)

文档不会出现这种情况,因为从用户的角度来看,地图确实具有类型(Int => Int) => BitSet。但是map还有一个更通用的类型,可以通过单击另一个链接进行检查。

我们尚未在工具中实现此类功能。但是我相信我们需要这样做,以避免吓跑人们并提供更多有用的信息。有了这样的工具,希望智能框架和库不会成为自杀记录。


107
我感觉像个调皮的男生!非常感谢您抽出宝贵的时间在这里回复。我认为答案的平衡向我表明,我不必担心。会有足够多的人完全不被吓到。
oxbow_lakes

164
不,我认为您绝对是正确的选择。除非我们对此有所作为,否则其他人会感到害怕。
Martin Odersky

33
马丁,我喜欢您的建议,以显示简化的方法签名,并在链接后隐藏一般细节。
德里克·马哈尔

18
我认为至少在文档中会有更多解释,这至少也可以起作用。如果不是因为大多数方法(甚至大多数类)没有一个以上的描述其目的和操作的句子,我就不会发现签名如此吓人。
尼克·约翰逊

98
更新:最终的Scala 2.8版本具有与我描述的机制类似的机制。如果在scaladocs中查找BitSet,则会发现:def map [B](f:(Int)⇒B):BitSet [B] [用例]通过将函数应用于此位集的所有元素来构建新集合。
马丁·

226

我既没有博士学位,也没有CS,数学或其他任何领域的学位。我没有使用Scala或任何其他类似语言的经验。我甚至没有远程可比类型系统的经验。实际上,我不仅拥有肤浅的知识,甚至拥有类型系统的唯一语言就是Pascal,但并不是以其复杂的类型系统而闻名。(尽管它确实具有范围类型,但AFAIK几乎没有其他语言具有范围类型,但这在这里并没有实际意义。)我知道的其他三种语言是BASIC,Smalltalk和Ruby,它们甚至都没有类型系统。

但是,我完全理解map您发布的功能的签名没有困难。在我看来,我map所见过的其他语言几乎都具有相同的签名。不同之处在于此版本更为通用。它看起来更像是C ++ STL,而不是Haskell。特别地,它仅通过要求参数为来抽象出具体的集合类型IterableLike,并且仅通过要求存在一个隐式转换函数来抽象出具体的返回类型,该隐式转换函数可以从结果值的集合中构建某些东西。是的,这很复杂,但这实际上只是通用编程的一般范例的表达:不要假设您实际上不需要做的任何事情。

在这种情况下,map实际上不需要将集合作为列表,排序或排序或类似的东西。唯一map关心的是它可以访问集合的所有元素,一个接一个,但是没有特定的顺序。而且,它不需要知道结果集合是什么,只需要知道如何构建它即可。因此,这就是其类型签名所需要的。

所以,代替

map :: (a → b)[a][b]

这是的传统类型签名map,它一般不需要具体ListIterableLike数据结构

map :: (IterableLike i, IterableLike j)(a → b) → i → j

然后通过仅要求存在一个可以结果转换为用户想要的任何数据结构的函数来进一步推广:

map :: IterableLike i ⇒ (a → b) → i → ([b] → c) → c

我承认语法有点笨拙,但语义是相同的。基本上,它从

def map[B](f: (A) ⇒ B): List[B]

这是的传统签名map。(请注意,由于Scala的面向对象性质,输入列表参数消失了,因为现在它是单调度OO系统中的每个方法都具有的隐式接收器参数。)然后将其从具体推广List到更一般IterableLike

def map[B](f: (A) ⇒ B): IterableLike[B]

现在,它用IterableLike可以产生,几乎任何东西的函数替换结果集合。

def map[B, That](f: A ⇒ B)(implicit bf: CanBuildFrom[Repr, B, That]): That

我真的相信是不是很难理解。实际上,您只需要几个智力工具:

  1. 您需要(大概)知道什么map。我承认,如果您只提供类型签名而没有方法的名称,那么弄清楚到底发生了什么会困难得多。但既然你已经知道什么map是应该做的,你知道它的类型签名应该是,你可以快速扫描的异常签名和重点,像“为什么这map需要两个函数作为参数,不是吗?”
  2. 您需要能够实际读取类型签名。但是,即使您以前从未见过Scala,这也应该很容易,因为它实际上只是您已经从其他语言中了解到的类型语法的混合:VB.NET使用方括号表示参数多态性,并使用箭头表示返回类型和冒号分隔名称和类型,实际上是规范。
  3. 您需要大致了解通用编程是什么。(是不是很难搞清楚,因为它基本上都在名字拼写出来:它真的只是一种通用的方式编程)。

这三个都不会使任何专业甚至业余程序员感到头疼。map在过去的50年中,几乎所有语言都已成为标准功能,对于使用HTML和CSS设计网站的人来说,不同的语言具有不同的语法这一事实应该显而易见,而您甚至不能订阅远程编程相关的邮件列表,但没有来自St.Stepanov教堂的令人讨厌的C ++狂人解释通用编程的优点。

是的,Scala 复杂。是的,Scala具有人类已知的最复杂的类型系统之一,与Haskell,Miranda,Clean或Cyclone等语言相抗衡甚至超越。但是,如果复杂性是反对编程语言成功的一个论点,那么C ++早就死了,我们所有人都在编写Scheme。Scala很有可能不会成功的原因很多,但是程序员坐在键盘前不必费心去动脑筋这一事实可能不会成为主要问题。


36
@Jorg-这是一个了不起的答案;谢谢。无论您是否拥有学位,您都比我聪明。我唯一的疑问是,我确实了解方法签名中正在发生的事情的大致情况。但是,细节仍然令人困惑:如何That推断和链接到类型B是一个浮现在脑海的问题。隐式从哪里来呢?即使没有这些详细的观察,我个人仍然认为这是一个复杂的签名。但是,显然有像您这样的人根本没有为此感到烦恼!
oxbow_lakes

50
很好的解释,但是您使我更加相信,Scala 2.8“ map”方法签名非常复杂。
德里克·马哈尔

11
看起来像这样的语言:def map [B](f:(A)⇒B):IterableLike [B]比看起来像这样的语言更具吸引力:def map [B,That](f:A⇒B )(隐式bf:CanBuildFrom [Repr,B,That]):那
Mark Essel

215
我觉得很有趣,您从声称只了解基本知识,红宝石和闲话开始,然后继续声称您对该主题没有任何学术背景。...然后在后来声称拥有Miranda和Clean等语言的类型系统的复杂性的知识;仅在严肃的编程语言极客和学者中才广为人知的语言。
萨米2010年

14
您有一个正确的点,就是与Haskell的比较是不正确的,因为“ map ::(a-> b)-> [a]-> [b]”特定于列表。但是,泛化版本(即Functor类的版本)仍然比Scala版本简单得多:类Functor f,其中fmap ::(a-> b)->
fa-

175

C ++中也是如此

template <template <class, class> class C,
          class T,
          class A,
          class T_return,
          class T_arg
              >
C<T_return, typename A::rebind<T_return>::other>
map(C<T, A> &c,T_return(*func)(T_arg) )
{
    C<T_return, typename A::rebind<T_return>::other> res;
    for ( C<T,A>::iterator it=c.begin() ; it != c.end(); it++ ){
        res.push_back(func(*it));
    }
    return res;
}

105
...他们说Scala晦涩难懂。!
missingfaktor

24
试想一下,如果使用正确的自我描述标识符而不是任意大写字母,将会是什么样子。:-)
Ti Strga

14
进行这种比较很有用,但是如果省略实现,那将更加公平。
亚伦·诺夫斯特鲁普

2
我不是强制函数指针的忠实拥护者。显然,的类型func应该是模板参数,并且您应该使用result_ofis_callable获取其他类型并适当地限制过载设置:-)
Kerrek SB

1
我眼睛疼 !!!
Ashkan Kh。Nazary

71

好吧,我能理解您的痛苦,但是坦率地说,像您和我这样的人-或几乎任何常规的Stack Overflow用户-都不是规则。

我的意思是……大多数程序员都不在乎那种类型签名,因为他们永远不会看到它们!他们不阅读文档。

只要他们看到了一些代码工作示例,并且代码没有使他们无法产生期望的结果,他们就永远不会看文档。如果失败,他们将查看文档,并期望在顶部看到用法示例

考虑到这些事情,我认为:

  1. 遇到该类型签名的任何人(大多数人)都会对Scala进行嘲笑,如果他们对Scala情有独钟,并且如果他们喜欢Scala,就会认为这是Scala力量的象征。

  2. 如果未对文档进行增强以提供用法示例并清楚说明方法的用途以及如何使用它,则可能会使Scala的采用有所降低。

  3. 从长远来看,这无关紧要。Scala 可以做类似的事情,这将使为Scala编写的库更加强大和安全。这些库和框架将吸引渴望使用强大工具的程序员。

  4. 喜欢简单性和直接性的程序员将继续使用PHP或类似语言。

Java,Java程序员非常喜欢电动工具,因此,在回答这一问题时,我刚刚修改了对主流Scala采用的期望。毫无疑问,Scala将成为主流语言。不是C主流,而是Perl主流或PHP主流。

说到Java,您曾经替换过类加载器吗?您是否曾经研究过涉及的内容?如果您看一下框架作家所做的事情,Java可能会令人恐惧。只是大多数人没有。恕我直言,同样的事情也适用于Scala,但是早期采用者倾向于查看他们遇到的每块岩石,以查看是否有藏身之处。


10
As long as they saw some example of how the code works, and the code doesn't fail them in producing the result they expect, they won't ever look at the documentation. When that fails, they'll look at the documentation and expect to see usage examples at the top.悲伤但真实。
gamliela

9
@gamliela,我认为我们不会为此感到难过。知识总是有多个层次可以应用,在任何系统中,他人的工作和信任(经过同行评审)总是可以被利用的,就像我们每天使用算术,而完全忽略了背后的可怕代数一样。
lcn

55

这会让人们不去斯卡拉吗?

是的,但这也可以防止人们被推迟。自从Scala获得对高类型类型的支持以来,我一直认为缺乏使用高类型类型的集合是一个主要弱点。它使API文档更加复杂,但实际上使用法更加自然。

这是否会使scala在商业世界中成为一个坏名声,因为只有专门的博士生才能理解这种学术玩法?CTO和软件负责人会被吓到吗?

有些可能会。我认为许多“专业”开发人员都无法使用Scala,部分原因是Scala的复杂性,部分原因是许多开发人员不愿学习。雇用此类开发人员的CTO会被吓到。

重新设计图书馆是明智的想法吗?

绝对。即使集合仍然有一些粗糙的边缘,它也使集合更适合其他语言和类型系统。

如果您在商业上使用Scala,您是否对此感到担心?您打算立即采用2.8还是等待观察会发生什么?

我没有在商业上使用它。我可能会等到至少有几个版本升级到2.8.x系列,然后再尝试引入它,以便可以清除错误。我还将拭目以待,看看EPFL在改进其发布和发行过程中取得了多少成功。我所看到的看起来很有希望,但我在一家保守的公司工作。

一个更普遍的话题是“ Scala对于主流开发人员来说是否太复杂了?” ...

大多数开发人员,不管是主流还是其他,都在维护或扩展现有系统。这意味着他们使用的大多数东西都是由很久以前做出的决定所决定的。仍然有很多人在编写COBOL。

明天的主流开发人员将致力于维护和扩展当今正在构建的应用程序。这些应用程序中有许多不是由主流开发人员构建的。明天的主流开发人员将使用当今最成功的新应用程序开发人员所使用的语言。


31
“这也将防止人们被推迟”。这个。绝对。scala是第一种使我们具有与haskell相当的功能(在其类型系统的能力下)的工程语言。我没有说服我使用haskell的方法,但是scala确实有机会,为此,我喜欢它,并且会(当我认为有道理的时候)会尝试使其接受或至少被接受,工作中。
安德鲁·库克

我也+1。考虑到Scala更加注重语言的深度和严谨性,而不是大众化的可及性,因此这些答案非常合适。
卡尔·斯莫特里兹

16
“明天的主流开发人员将使用当今最成功的新应用程序开发人员所使用的语言。” +1。精采地说。
Vasil Remeniuk

46

Scala社区可以减轻对Scala新手程序员的恐惧的一种方法是,专注于实践并通过示例进行教学-许多示例从小处开始,逐步发展为大。以下是一些采用这种方法的站点:

在这些站点上花了一些时间后,人们很快意识到Scala及其库,尽管可能难以设计和实现,但使用起来并不难,尤其是在常见情况下。


43

我从廉价的“大众市场”美国大学获得了本科学位,所以我会说我处于用户智能(或至少是教育)规模的中间:)我刚接触Scala几个月了并曾开发过两个或三个非同寻常的应用程序。

尤其是现在IntelliJ发布了其精美的IDE并附带了IMHO目前最好的Scala插件,Scala的开发相对来说比较轻松:

  • 我发现我可以将Scala用作“没有分号的Java”,即,我写的代码看起来与Java相似,并且从语法简洁性(例如类型推断)中受益匪浅。当我完全执行异常处理时,它更方便。如果没有getter / setter样板,则类定义的详细程度将大大降低。

  • 偶尔我会写一行来完成多行Java的等效。在适用的情况下,功能性方法链(如地图,折叠,收集,过滤器等)的构成有趣且优雅。

  • 我很少能从Scala的更强大功能中受益:闭包和部分(或咖喱)功能,模式匹配等。

作为新手,我继续努力使用简洁和惯用的语法。没有参数的方法调用除了需要括号外,不需要括号。match语句中的案例=>需要粗箭头(->),但在某些地方还需要细箭头()。许多方法的名称简短/:或含糊不清,例如或\:-如果翻转足够多的手册页就可以完成工作,但是我的某些代码最终看起来像Perl或行噪声。具有讽刺意味的是,语法速记中最受欢迎的位之一在实际操作中丢失了:我一直被Int未定义++方法的事实所困扰。

这只是我的看法:我觉得Scala具有C ++的功能以及C ++的复杂性和可读性。该语言的语法复杂性也使API文档难以阅读。

Scala 经过深思熟虑,在许多方面都很出色。我怀疑许多学者愿意在其中编程。但是,它也充满了聪明和陷阱,它的学习曲线比Java高得多,并且很难阅读。如果我仔细研究论坛,看看有多少开发人员仍在为Java的优缺点而苦苦挣扎,那么我将无法想到Scala曾经成为主流语言。没有公司能够证明其开发人员参加为期3周的Scala课程,而以前他们只需要进行1周的Java课程。


9
对不起,所有评论。1周几乎是所有语言的笑话,但这并不妨碍经理们将这种笑话付诸实践。我曾经有3天的时间将一组C ++开发人员“速成”到Java中。我要求了5天,但由于预算原因而缺席。
2009年

22
对于我的第一份工作,在面试结束时给了我一本C ++书籍,以便在星期一开始工作之前学习。你们都是好事。
Tom Hawtin-抢险活动

12
@Tom @Erik你们这些男孩很容易。我得到了电路图到计算机(当时没有CPU),并告诉我有两个小时的时间来修复一个错误,作为采访。
Daniel C. Sobral

33
@Daniel @Tom @Erik我曾经被赋予0和1,并被要求在面试过程中使用它们来解决线性时间的背包问题。我试了一下,但是不幸的是,我只有时间来创建Eclipse(我怀疑它可以简化为背包)。#tall_tale
亚历克斯·米勒

10
@Alex这表明缺乏想象力。在左侧放置一个大零,在右侧放置另外两个较小的零:一个在另一个上方,顶部一个在左侧。将一个放在这两个较小的零之间,从左下角到右上角。假设这是在线性时间内解决背包问题的机会。到此,您就完成了。:-) +1等同于Eclipse和Knapsack。:-)
Daniel C. Sobral

33

我认为该方法的主要问题是(implicit bf : CanBuildFrom[Repr, B, That])没有任何解释。即使我知道隐式参数是什么,也没有任何迹象表明这会如何影响调用。追踪scaladoc只会让我更加困惑(很少有CanBuildFrom甚至有文档相关的类)。

我认为简单的“范围内必须有一个隐式对象bf,可以为B返回类型的类型提供对象的构建器That”会有所帮助,但是当您真正想做的只是map AB的。实际上,我不确定这是正确的,因为我不知道类型的Repr含义,而且有关该文档的资料Traversable当然也毫无头绪。

因此,我有两个选择,两个都不令人愉快:

  • 假设它将只适用于旧地图的工作方式以及大多数其他语言的地图工作方式
  • 深入研究源代码

我知道Scala本质上是在揭示这些事情的工作原理,最终这提供了一种执行oxbow_lakes描述的方式的方法。但这会分散签名的注意力。


2
Repr是可遍历的表示,即。ListSetMap。我认为,作为一个框架,如果您要开始查看方法签名(而不是仅通过复制示例来使用方法),则必须首先了解常规设计。恕我直言,Scaladoc应该充满示例用法
oxbow_lakes

10
那么,我将如何确定Repr含义呢?我希望在scaladoc中有一个解释,但对我而言确实不那么明显。我认为这是scaladoc中的常见模式(请看,Actor.react并且Actor.receive-我被告知,并且已经看到,他们做的事情完全不同,但是scaladoc是相同的)。
davetron5000

7
我同意davetron5000。我对Scala相当熟悉,但是隐式定义仍然让我头痛。原因不是本质上的隐含,而是原因。绝对应该有更好的文档和工具支持来了解Scala类型。就是说,我认为类型系统确实具有重要的作用。但是我们仍然只是明智编程的开端。
egaga

22

我是Scala初学者,老实说我看不到该类型签名的问题。参数是要映射的函数,隐式参数是构建器以返回正确的集合。清晰可读。

实际上,整个过程非常优雅。构建器类型参数使编译器选择正确的返回类型,而隐式参数机制则向类用户隐藏此额外参数。我尝试了这个:

Map(1 -> "a", 2 -> "b").map((t) => (t._2) -> (t._1)) // returns Map("a" -> 1, "b" -> 2)
Map(1 -> "a", 2 -> "b").map((t) =>  t._2)            // returns List("a", "b")

那是正确的多态性。

现在,这已经不是主流范式了,它会吓跑许多人。但是,它也会吸引许多重视它的表现力和优雅的人。


20

不幸的是,您提供的地图签名是不正确的地图签名,确实存在合法的批评。

第一个批评是,通过颠覆地图的签名,我们得到了更普遍的东西。普遍认为,默认情况下这是一种美德。不是。映射函数非常好地定义为协变函子Fx->(x-> y)-> Fy,并遵守组成和同一性两个定律。归因于“地图”的任何事物都是愚蠢的。

给定的签名是其他东西,但不是地图。我怀疑它试图成为论文“迭代器模式的本质”中“遍历”签名的专业化版本,并对其进行了稍微改动。这是它的签名:

traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)

我将其转换为Scala:

def traverse[A, B](f: A => F[B], a: T[A])(implicit t: Traversable[T], ap: Applicative[F]): F[T[B]

当然会失败-这还不够普遍!而且,它略有不同(请注意,您可以通过在Identity函子上运行导线来获得地图)。但是,我怀疑如果库作者更加了解有据可查的库概括(前面提到的带效果的应用程序编程),那么我们不会看到此错误。

其次,地图功能在Scala中是一种特殊情况,因为它用于理解。不幸的是,这意味着装备精良的图书馆设计人员在不牺牲理解力的语法糖的情况下不能忽略该错误。换句话说,如果Scala库设计者要销毁一种方法,那么很容易忽略它,但是请不要映射!

我希望有人大声疾呼,因为事实上,解决Scala坚持犯的错误将变得更加困难,这显然是出于我强烈反对的原因。也就是说,解决“普通程序员不负责任的反对(即太难了!)”的解决方案不是“安抚他们以使他们更容易”,而是提供指导和帮助以成为更好的程序员。我自己和Scala的目标都在这个问题上争论不休,但回到您的观点。

您可能是在指出自己的观点,并预测“普通程序员”的具体回应。就是说,那些声称“但是太复杂了”的人!或类似的东西。这些是您引用的Yegges或Blochs。我对这些反智主义/实用主义运动的人的反应相当严厉,而且我已经预料到会有一系列反应,因此我将省略。

我真的希望Scala库能够有所改善,或者至少可以将错误放到一个角落里。Java是一种“试图做任何有用的事情”的代价之高的语言,通常不值得这样做,因为无法避免绝大多数错误。我恳求Scala不要走同一条路。


3
嗨,托尼-感谢您在这里的体贴。我会对此做出2条回应。首先,我没有提到“普通程序员”,也不相信Scala一定是针对一个程序员的。无论是自负还是自负,我都认为自己高于平均水平。但是,我仍然觉得类型签名令人生畏!换句话说,我仍然担心,高于平均水平的程序员(Scala的目标市场)可能会被赶走。
oxbow_lakes

6
第二点是,我从根本上不同意Scala 什么:Scala是一种实用的语言,而不是理论上纯净的语言。为什么还要在JVM上进行设计?这纯粹是务实的决定-它针对的是“现实世界”中的开发人员-这种选择可能需要妥协!另请注意,Bloch和Yegge与普通程序员相距甚远-但这是我的观点。即使是受人尊敬和有才华的人,也可能对您的复杂性和纯度有不同的看法。不幸的是,它们也很有影响力。
oxbow_lakes

3
您好oxbow_lakes,即使以准确性和实用性为代价,Scala的既定目标也是安抚典型的程序员。超出平均水平的程序员被赶走了(我有很多轶事),但这并不是因为类型签名令人生畏,而是由于某些错误的性质。我不是说Scala是实用的还是理论的。此外,我什至不赞成这种二分法存在的(普通?)想法。Scala库已将地图签名弄错了。多年来,我一直在努力解决Scala的错误;特别是图书馆。是时候再做一次。
托尼·莫里斯

5
我不认为布洛赫(Bloch)或叶格(Yegge)是受人尊敬或聪明的人,但他们确实很有影响力。是的,这很不幸。
托尼·莫里斯

9
为什么将导线遍历与Scala的扩展签名相关联?对于单功能者,Scala的地图是标准的fmap。但是BitSet和Map [A​​,B]都不是单功能的,而map在它们上面有一个有意义的定义。这就是Scala签名的动机,而遍历并不能解决这个问题。为什么普遍性是一件坏事?应用函子跟踪效果,它们在Scala中有什么意义?最后,我相信Scala的通用映射可以通过广义遍历的方式实现,接受CanBuildFrom并返回可能不同的Traversable:无需牺牲理解力!
Blaisorblade 2011年

15

我完全同意这个问题和马丁的回答:)。即使是在Java中,由于存在额外的噪音,使用泛型读取javadoc也比应做的要难得多。这在Scala中变得更加复杂,在Scala中,隐式参数与问题的示例代码一样使用(而隐式参数对集合变形非常有用)。

我认为语言本身没有问题-我认为它更多是工具问题。尽管我同意JörgW Mittag的观点,但我认为查看scaladoc(或您的IDE中类型的文档)时-应该只需要尽可能少的脑力就能理解方法的含义,方法的使用和返回。不需要在纸上乱写一些代数就可以了:)

可以肯定的是,IDE需要一种很好的方式来显示任何变量/表达式/类型的所有方法(就像Martin的示例一样,可以内联所有泛型,因此很容易理解)。我也喜欢Martin的默认隐藏隐藏内容的想法。

以scaladoc为例...

def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That

当在scaladoc中查看时,我希望默认情况下隐藏通用块[B,That]以及隐式参数(也许如果您用鼠标悬停了一个小图标,它们就会显示)-作为其多余的东西阅读它通常没有什么关系。例如,假设这看起来像...

def map(f: A => B): That

清晰明了,它的作用。您可能想知道“那个”是什么,如果您将鼠标悬停或单击它,它可能会展开突出显示“那个”的[B,That]文本。

也许可以在[]声明和(implicit ...)块中使用一个小图标,以便清楚地看到该语句的一点点折叠了?很难使用令牌,但我将使用。目前...

def map.(f: A => B).: That

因此,默认情况下,类型系统的“噪声”隐藏在人们需要查看的主要80%的内容中-方法名称,其参数类型和其返回类型都以简洁明了的方式-几乎没有可扩展的细节链接如果您真的很在乎。

通常,人们正在阅读scaladoc,以了解他们可以在类型上调用哪些方法以及可以传递哪些参数。我们有点给用户过多的内容,就像恕我直言。

这是另一个例子

def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1]

现在,如果我们隐藏泛型声明,它更容易阅读

def orElse(that: PartialFunction[A1, B1]): PartialFunction[A1, B1]

然后,如果人们将鼠标悬停在A1上,我们可以证明A1的声明为A1 <:A。泛型中的协变和逆变类型也增加了很多噪音,对于我认为的用户,可以更容易理解的方式呈现。


5
但是,“那个”作为结果类型是什么意思?
Blaisorblade 2011年

11

我不知道如何将它破解,但是我有剑桥大学的博士学位,我使用2.8很好。

更严重的是,我几乎没有花任何时间使用2.7(它不会与我正在使用的Java库进行互操作),而是在一个月前开始使用Scala。我对Haskell有一定的经验(不多),但是只是忽略了您担心的内容,而是寻找与我的Java经验相匹配的方法(我以此为生)。

所以:我是一个“新用户”,但我并没有推迟-它像Java一样工作,这给了我足够的信心来忽略我不理解的部分。

(但是,我查看Scala的部分原因是看是否要在工作中使用它,而我现在还不会这样做。使文档减少威胁程度当然会有所帮助,但令我惊讶的是它仍然有多少改变和发展(公平的说,最让我惊讶的是它的强大,但是紧随其后的是变化。)所以我想我想说的是,我宁愿将有限的资源投入到它的开发中最终状态-我认为他们不会很快就这么受欢迎。)


22
我想他想知道没有剑桥大学博士学位的人是否可以使用Scala 2.8。
肯·布鲁姆(

2
哈哈:感动!好吧,我说过scala 2.8易于使用-我的问题更多是关于浏览API以查看他们是否喜欢它的人的外观,假设他们以前没有使用Scala的经验。
oxbow_lakes 2009年

1
@andrew-从yout网站(acooke.org)的外观来看,您对视觉上令人生畏的概念并不感到不舒服
oxbow_lakes

任何从事Malbolge编程的人,即使只是“ Hello World”,也不大可能被任何事情吓倒。
卡尔·斯莫特里奇

10

完全不了解Scala,但是几个星期前我看不懂Clojure。现在,我可以阅读其中的大部分内容,但是除了最简单的示例之外,还无法编写任何内容。我怀疑Scala没什么不同。根据您的学习方式,您需要一本好书或一门课程。仅阅读上面的地图声明,我大概得到了其中的1/3。

我认为更大的问题不是这些语言的语法,而是采用和内部化了使它们在日常生产代码中可用的范例。对我而言,Java并不是C ++的巨大飞跃,也不是C的巨大飞跃,它也不是Pascal,Basic等的飞跃。但是,使用Clojure这样的功能语言进行编码一个巨大的飞跃(对于无论如何还是我。我猜在Scala中,您可以使用Java样式或Scala样式进行编码。但是在Clojure中,您将造成混乱,试图使您的命令式习惯远离Java。


5
它与符号无关(或与符号无关,不超过10-15%),而总是与概念有关。而且,如果您有足够的才智,并且数十年来没有从不同的,可能相互矛盾的模型(如我所见)中了解知识,那么通常掌握这些东西就不会太困难。但是,如果您沉迷于一种思考和做事的方式,那么至少需要做出一些努力来适应这种变化,并且许多人会对此做出反应。这只是人类的心理/自然。(我想知道温伯格的计算机编程心理学在将近40年后如何保持?)
Randall Schulz 2010年

1
@Randall Schultz和Jeff G:对于聪明人来说,语法/符号相当容易。基本上,相同概念的名称不同。掌握一种新语言只是一个实践问题。但是,从过程编程到函数式编程的步骤令人震惊。这实际上是一种不同的思维方式。我已经接触Clojure几个月了,发现它是一种相对“简单”,令人愉悦的FP语言。但是我仍然需要花费大量时间来弄清楚在过程编程中很简单的东西。
卡尔·斯莫特里奇

7

Scala具有许多疯狂的功能(尤其是在涉及隐式参数的情况下),这些功能看起来非常复杂且具有学术性,但旨在使事情易于使用。最有用的语法句法糖(例如[A <% B],这意味着类型A的对象具有对类型B的对象的隐式转换),并对其进行了详细记录的解释。但是大多数时候,作为这些库的客户端,您可以忽略隐式参数,并信任它们做正确的事情。


是的,视图语法使事情变得更容易掌握。
egaga

6

这会让人们不去斯卡拉吗?

我认为这不是影响Scala受欢迎程度的主要因素,因为Scala具有强大的功能,并且其语法对Java / C ++ / PHP程序员而言并不像Haskell,OCaml,SML,Lisps,等等..

但是我确实认为Scala的普及程度将不会达到Java的水平,因为我还认为,下一代主流语言必须大大简化,而且我看到的唯一方法就是纯不变性,即像HTML这样的声明性语言,但图灵完成了。但是,我有偏见是因为我正在开发这样的语言,但是只有在排除了几个月的研究后,Scala无法满足我的需要之后,我才这样做。

这是否会使Scala在商业世界中成为坏名声,因为只有专业的博士生才能理解这种学术玩法?CTO和软件负责人会被吓到吗?

我认为Scala的声誉不会因为Haskell复杂性而受到影响。但是我认为有些人会推迟学习它,因为对于大多数程序员而言,我还没有看到强迫他们使用Scala的用例,他们会拖延学习它的时间。高度可扩展的服务器端也许是最引人注目的用例。

而且,对于主流市场而言,首先学习Scala并不是“新鲜呼吸”,而是立即编写程序,例如首先使用HTML或Python。在人们从一开始就学到了所有偶然发现的细节之后,Scala往往会在你身上成长。但是,也许如果我从一开始就读过《 Scala编程》,那么我对学习曲线的经验和看法就会有所不同。

重新设计图书馆是明智的想法吗?

绝对是

如果您正在商业上使用Scala,您是否对此感到担心?您打算立即采用2.8还是等待观察会发生什么?

我正在使用Scala作为新语言的初始平台。如果我不以商业方式使用Scala,则可能不会在Scala的集合库上构建代码。我会创建自己的基于类别理论的库,因为有一次我发现,我发现Scalaz的类型签名比Scala的集合库更加冗长和笨拙。这个问题的一部分可能是Scala实现类型类的方式,这是我创建自己的语言的一个次要原因。


我决定写这个答案,因为我想强迫自己研究和比较Scala的集合类设计与我为我的语言所做的设计。不妨分享我的思考过程。

2.8 Scala集合使用生成器抽象是合理的设计原则。我想在下面探讨两个设计权衡。

  1. 仅写代码:写完本节后,我阅读了Carl Smotricz的评论,该评论与我希望进行的折衷相一致。James Strachan和davetron5000的评论都认为,That(甚至不是That [B])的含义以及隐式机制都不容易直观地理解。请参阅下面的问题2中我对monoid的使用,我认为它更为明确。德里克·马哈(Derek Mahar)的评论是关于编写Scala的,但是对于阅读不是在“普通情况下”的其他人的Scala的评论又如何呢?

    我读到的有关Scala的一种批评是,编写它比阅读其他人编写的代码容易。而且我发现由于各种原因(例如,编写函数的多种方式,自动关闭,DSL的单位等),偶尔会出现这种情况,但是我不确定这是否是主要因素。在这里,隐式函数参数的使用有其优点和缺点。从好的方面来说,它减少了详细程度并自动选择了构建器对象。以奥德斯基为例从BitSet(即Set [Int])到Set [String]的转换是隐式的。陌生的代码阅读者可能不容易知道集合的类型,除非他们能够很好地推断当前包范围中可能存在的所有潜在隐式隐式生成器候选对象。当然,经验丰富的程序员和代码编写者将知道BitSet限于Int,因此到String的映射必须转换为其他集合类型。但是,哪种收集类型?没有明确指定。

  2. 临时集合设计:写完本节后,我阅读了托尼·莫里斯(Tony Morris)的评论,并意识到我的观点差不多。也许我更详细的阐述会使观点更清楚。

    在Odersky&Moors的“与类型战斗”中,提出了两个用例。它们是BitSet限制为Int元素,而Map限制为成对元组元素,并且被提供为通用元素映射函数A => B必须能够构建替代目标集合类型的原因。但是,从类别理论的角度来看,这是有缺陷的。为了在类别理论上保持一致并避免出现极端情况,这些集合类型是仿函数,其中每个态素A => B必须在同一仿函数类别List [A] => List [B],BitSet中的对象之间映射[A] => BitSet [B]。例如,一个选项是一个函子,可以看作一个Some(object)和None的集合的集合。从Option的None或List的Nil到没有

    这里有一个折衷的设计选择。在我的新语言的馆藏设计库中,我选择将所有内容都设为函子,这意味着,如果我实现BitSet,则在使用非位字段表示时,它需要使用非位字段内部表示形式来支持所有元素类型。整数类型参数,并且该功能已经存在于它在Scala中继承的Set中。我设计中的Map仅需要映射其值,并且它可以提供一个单独的非函数方法来映射其(键,值)对元组。一个优点是,每个函子通常也是一个可应用的函数,也可能是一个monad。因此,元素类型之间的所有功能(例如A => B => C => D => ...)将自动提升为提升的应用类型之间的功能,例如List [A] => List [B] => List [ C] =>列表[D] =>...。对于从函子到另一个集合类的映射,我提供了一个映射重载,该重载采用了一个monoid,例如Nil,None,0,“”,Array()等。因此,构建器抽象函数是monoid和作为必需的输入参数显式提供,因此没有不可见的隐式转换。(切线:此输入参数还允许附加到非空的Monoid,这是Scala的地图设计无法做到的。)此类转换是地图和同一遍遍中的折叠。另外,我提供了一种可遍历的类别“具有效果的应用程序编程” McBride&Patterson,它还允许一次遍历从任何可遍历到任何可应用程序的map + fold遍历,其中大多数每个收集类都是两者。

    因此,从非范畴论的角度而言,Scala集合的fafas是“即席的”,范畴论是高级指称语义的本质。尽管Scala的隐式生成器最初看起来比函子模型+ monoid生成器+可遍历->应用性更“泛化”,但它们的确不符合任何类别,因此我们不知道它们在遵循什么规则最一般的意义以及给出的特殊情况,它们可能不遵循任何类别模型。添加更多的变量会使某些事情变得更笼统是不正确的,这是范畴论的巨大好处之一,因为它提供了在保持更高泛泛语义的同时保持普遍性的规则。集合是一个类别。

    我在某处读过文章,我认为是Odersky,这是库设计的另一个理由是,纯函数式编程的代价是有限的递归和速度,而没有使用尾递归。到目前为止,我没有发现很难在所有情况下都采用尾递归。


另外,我在脑海中提出一个不完整的想法,即Scala的某些折衷是由于试图既是可变的又是不变的语言,与Haskell或我正在开发的语言不同。这与托尼·莫里斯的理解有关。用我的语言,没有循环,也没有可变的构造。我的语言(目前)将位于Scala之上,这要归功于它,如果Scala没有通用的类型系统和可变性,这将是不可能的。但是,这可能不是正确的,因为我认为Odersky&Moors(“用类型来对抗位旋转”)不正确地指出Scala是唯一一种具有较高种类的OOP语言,因为我(通过我自己和通过Bob Harper)验证了该标准ML有他们。看起来SML的类型系统可能具有同等的灵活性(自1980年代起),由于语法与Scala不太像Java(和C ++ / PHP),因此可能不容易理解。无论如何,这都不是对Scala的批评,而是试图对权衡取舍进行不完整的分析,我希望这与该问题密切相关。Scala和SML不会因为Haskell的无能为力而受苦菱形多重继承,这很关键,我知道这就是为什么Haskell Prelude中的这么多函数针对不同类型进行重复。


那么,您的语言会面向对象吗?
missingfaktor 2011年

是的,继承了Scala的类型系统。一个关键的区别是特征被分为接口和混合,其中接口仅包含方法签名而没有实现。并且只能将接口引用为类型。消除了隐式隐式,并在接口中以SPOT方式处理类型类。这是细节的草稿。欢迎合作者。该库的一些代码在这里。这项工作仍在进行中,很抱歉提及气相色谱仪。只是分享想法。
谢尔比·摩尔三世

5

似乎有必要在这里陈述学位:政治学学士学位和计算机科学学士学位。

要点:

这会让人们不去斯卡拉吗?

Scala很难,因为它的基础编程范例很困难。函数式编程使很多人感到恐惧。可以用PHP构建闭包,但人们很少这么做。因此,不,不是这个签名,而是其他所有人,如果他们没有经过特殊的教育以使他们珍视基础范式的力量,就会使他们失望。

如果可以接受这种教育,那么每个人都可以做到。去年,我在SCALA与一群在校学生一起建造了国际象棋计算机!他们遇到了问题,但最终还是不错。

如果您正在商业上使用Scala,您是否对此感到担心?您打算立即采用2.8还是等待观察会发生什么?

我不会担心。


4

我也有牛津大学的数学学位!我花了一段时间才“得到”新的收藏品。但是我现在非常喜欢它。实际上,“ map”的输入是2.7中困扰我的第一批大事(也许因为我做的第一件事是集合类之一的子类)。

阅读Martin关于新2.8集合的论文确实有助于解释隐式方法的使用,但是是的,文档本身肯定需要做得更好,以解释不同类型的隐式方法在核心API的方法签名中的作用。

我主要关心的是:2.8什么时候发布?错误报告何时会停止出现?Scala团队是否被2.8咬伤/试图一次改变太多?

我真的很想将2.8稳定下来作为发布的优先级,然后再添加其他新内容,并且想知道(边观望)是否可以对scala编译器的开发路线图的管理方式进行一些改进。


-1

使用中的错误消息如何处理?

那么,用例何时需要将现有类型与适合DSL的自定义类型集成在一起。必须对相关性,优先级,隐式转换,隐式参数,更高种类以及可能存在的类型进行良好的教育。

很高兴知道大多数情况下它很简单,但并不一定足够。如果要设计广泛的库,至少必须有一个知道这些知识的人。


但主要要点之一是从用户和创建者的角度来看库之间的区别。显然,创建者需要深刻了解所需的语言功能(例如,更高种类的类型,隐式优先级)-问题是:“用户吗?”
oxbow_lakes
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.