web-dev-qa-db-ja.com

Scala 2.8コレクションライブラリは、「史上最長の自殺記録」の例ですか?

Scala collections library re-implementation が間近に迫っています2.8リリースに目を向け始めました。 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に来る人を先送りするでしょうか?
  • これはScalaを商業の世界でアカデミックな遊び道具として悪い名前にするのでしょうか? CTO sとソフトウェアの責任者は怖がりますか?
  • ライブラリの再設計は賢明なアイデアでしたか?
  • Scalaを商業的に使用している場合、これについて心配していますか? 2.8をすぐに採用する予定ですか、それとも何が起こるのを待つのですか?

Steve Yegge一度Scalaを攻撃した (私の意見では間違っている)彼がその複雑な型システムとして見たものに対して。誰かがこのAPIで FUD を延期することになるのではないかと心配しています(Josh Blochが JCP をJavaに追加することを怖がらせたのと同様) 。

-明確にすべきですが、 Joshua Bloch はBGGA閉鎖提案の拒否に影響を与えたと思いますが、そうではありませんこれは、提案が間違いであるという彼の誠実な信念以外の何かに帰せられます。


私の妻と同僚が私に言い続けていることにもかかわらず、私はばかだとは思わない:私は数学でかなりの学位を持っている オックスフォード大学 、そして私はほとんど商業的にプログラミングをしている12年と Scala で約1年間(また商業的に)。

炎症性の主題のタイトルは 英国の政党のマニフェストについての引用 1980年代初頭であることに注意してください。この質問は主観的ですが、それは純粋な質問です。私はCWにしたので、この問題について意見を聞きたいと思います。

860
oxbow_lakes

それが「自殺メモ」ではないことを願いますが、私はあなたの主張を理解することができます。あなたは同時に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になりますが、IntsをStringsにマップすると一般的なSetになります。マップの結果の静的型と実行時表現はどちらも、渡される関数の結果型によって異なります。そしてこれは集合が空の場合でも機能するので、関数は決して適用されません!私の知る限りでは、同等の機能を持つ他のコレクションフレームワークはありません。しかし、ユーザーの観点からすると、これはどのように動作すると想定されているかです。

私たちが抱えている問題は、これを可能にするすべての巧妙な技術が、大きくなり怖くなる型シグネチャに漏れることです。しかし、多分ユーザーはmapのフルタイプシグネチャをデフォルトで表示されるべきではないでしょうか。 mapBitSetを検索した場合はどうでしょうか。

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

ユーザーの観点からすると、実際にマップの型は(Int => Int) => BitSetであるため、ドキュメントはその場合には当てはまりません。しかしmapにはもっと一般的な型もあり、他のリンクをクリックすることで調べることができます。

私たちのツールにはこのような機能はまだ実装されていません。しかし、私たちはこれを行う必要があると思います。人々を追い払うのを避け、より有用な情報を提供するためです。そのようなツールでは、うまくいけばスマートなフレームワークとライブラリは自殺メモにならないでしょう。

874
Martin Odersky

私は博士号もCSも数学も他の分野の学位も持っていません。 Scalaや他の類似言語の経験はありません。リモートに匹敵するタイプのシステムでさえ経験がありません。実際、私がhas型システムでさえも表面的な知識以上のものを持っている唯一の言語はPascalであり、その洗練された型システムでは正確に知られていません。 (それはdoesですが、他の言語にはほとんどないAFAIKの範囲タイプがありますが、ここではあまり関係ありません。)私が知っている他の3つの言語はBASIC、Smalltalk、Rubyです。型システムもあります。

それでも、あなたが投稿したmap関数のシグネチャを理解するのに全く問題はありません。 mapが私が今まで見た他のすべての言語で持っているのとほとんど同じ署名のように見えます。違いは、このバージョンがより一般的であることです。 HaskellよりもC++ STLのように見えます。特に、引数がIterableLikeであることのみを要求することにより、具体的なコレクション型から抽象化します。また、構築可能な暗黙の変換関数が存在することのみを要求することにより、具体的な戻り値型から抽象化します何か結果値のコレクションのうち。はい、それは非常に複雑ですが、実際には汎用プログラミングの一般的なパラダイムの表現にすぎません。実際に必要のないことを想定しないでください。

この場合、mapは実際には必要コレクションではなく、リストであるか、順序付けされているか、ソート可能であるか、またはそのようなものではありません。 mapが気にする唯一のことは、コレクションのすべての要素に順番にアクセスできることです。ただし、順不同です。そして、結果のコレクションが何であるかを知る必要はありません。それを構築する方法を知るだけです。したがって、それがその型シグネチャに必要なものです。

だから、代わりに

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

これはmapの従来の型シグネチャであり、具体的なListではなく、単にIterableLikeデータ構造を必要としないように一般化されています

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

次に、convert結果をユーザーが望むデータ構造に変換できる関数が存在することのみを要求することにより、さらに一般化されます。

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結果コレクションをproducesという関数に置き換えています。

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

私が本当に信じているのはthat理解しにくいことではありません。本当に必要な知的ツールは数種類しかありません。

  1. mapとは(大体)知る必要があります。 onlyメソッドの名前なしでタイプシグネチャを指定した場合、何が起こっているのかを把握するのがはるかに難しくなります。しかし、あなたはすでにknowmapが何をすべきであり、そのタイプ署名が何であるかを知っているので、署名をすばやくスキャンして、「理由」などの異常に集中できます。このmapは、1つではなく2つの関数を引数として取りますか?」
  2. 実際にread型署名ができる必要があります。しかし、Scalaを一度も見たことがなくても、他の言語で既に知っている型構文の混合物であるため、これは非常に簡単です。VB.NETはパラメトリック多相性に角括弧を使用します。矢印を使用して戻り値の型を示し、コロンを使用して名前と型を区切るのが実際です。
  3. 汎用プログラミングとは何かを大まかに知る必要があります。 (これはthat理解するのが難しいことではありません。基本的にすべて名前で綴られているためです。文字通り一般的な方法でプログラミングしているだけです)。

これらの3つのいずれも、プロのプログラマーや趣味のプログラマーに深刻な頭痛を与えるべきではありません。 mapは、過去50年間に設計されたほとんどすべての言語の標準機能でした。HTMLとCSSを使用してWebサイトを設計した人は、言語ごとに構文が異なるため、購読できません。聖ステパノフ教会の一部の迷惑なC++ファンボーイが一般的なプログラミングの長所を説明することなく、リモートプログラミング関連のメーリングリストにも。

はい、Scala is complex。はい、Scalaには、Haskell、Miranda、Clean、Cycloneなどの言語に匹敵する、さらには言語を凌evenする、人間に知られている最も洗練されたタイプシステムの1つがあります。しかし、複雑さがプログラミング言語の成功に対する議論であれば、C++はずっと前に亡くなっていたでしょうし、私たちは皆Schemeを書いているでしょう。 Scalaが成功しない可能性が非常に高い理由はたくさんありますが、キーボードの前に座る前にプログラマが頭を悩ませることができないという事実はおそらくそうではないでしょう主なもの。

223
Jörg W Mittag

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;
}
169
skyde

うん、私はあなたの苦痛を理解することができます、しかし、率直に言って、あなたと私のような人々 - あるいはほとんどすべての通常のStack Overflowユーザ - はルールではありません。

つまり、ほとんどのプログラマはその型シグネチャを気にする必要はありません。なぜなら、彼らは決してそれらを見ることはないからです!彼らはドキュメンテーションを読みません。

彼らがコードのしくみのいくつかの例を見て、コードが彼らが期待する結果を生み出すのに失敗しない限り彼らはそうしませんドキュメントを見てください。それが失敗したとき、彼らはドキュメンテーションを見て、上部に使用例を見ることを期待するでしょう。

これらのことを念頭に置いて、私はそれを思います:

  1. そのタイプのシグニチャに遭遇したことがある人(ほとんどの人がそうであるように)は、Scalaをそれに対して事前に処分されている場合に限りなく終わりまでモックアップします。

  2. 使い方の例を提供し、そのメソッドが何のためのものでどのように使用するのかを明確に説明するためにドキュメントが拡張されていない場合は、Scalaの採用を少し損なうことがあります。

  3. 長い目で見れば、それは問題になりません。そのようなScalaできることは、Scala用に書かれたライブラリをより強力で安全に使用できるようにします。これらのライブラリとフレームワークは、強力なツールに魅了されているプログラマーを引き付けるでしょう。

  4. 単純さと直接的さを好むプログラマーは、引き続きPHPやそれに類似した言語を使用するでしょう。

残念ながら、Javaプログラマーは強力なツールに精通しているので、それに答えて、私はScalaの主流採用の私の期待を修正しました。私はScalaが主流の言語になることには疑いない。 Cメインストリームではなく、おそらくPerlメインストリームまたはPHPメインストリーム。

Javaと言えば、クラスローダーを置き換えたことはありますか?あなたはこれが何を含むのかを調べたことがありますか?フレームワークを書く人がする場所を見ると、Javaは怖いかもしれません。ほとんどの人がそうではないということです。同じことが私見のScalaにもあてはまりますが、初期の採用者は遭遇するそれぞれの岩の下を見て、そこに隠れているものがあるかどうかを確認する傾向があります。

70

これで人々がScalaにやってくるのをやめるのでしょうか。

はい、しかしそれはまた人々が延期されるのを防ぎます。 Scalaが高階型をサポートして以来、高階型を使用するコレクションの欠如が大きな弱点となっていました。それはAPIドキュメントをより複雑にします、しかしそれは本当に使い方をより自然にします。

これは、専任の博士課程の学生しか理解できない学術的な玩具として、scalaに商業的世界で悪い名前を付けることになるでしょうか? CTOやソフトウェアの責任者たちは怖がるのでしょうか。

おそらくそうなるでしょう。私はScalaが多くの「プロの」開発者にとって利用しやすいとは思いません。これは、Scalaの複雑さと、多くの開発者の学習意欲の欠如のためです。そのような開発者を雇用しているCTOは当然怖がっているでしょう。

図書館は賢明なアイデアを再設計しましたか?

もちろんです。それは、たとえそれがまだいくらかの粗い縁を持っていたとしても、コレクションが残りの言語と型システムとはるかによく合うようにします。

あなたがScalaを商業的に使っているなら、あなたはこれを心配していますか?あなたはすぐに2.8を採用する予定ですか、それとも何が起こるのを待つことを予定していますか?

私は商業的には使っていません。私はおそらくバグがフラッシュされることができるようにそれを導入しようとさえする前に少なくともカップルが2.8.xシリーズに回転するまで待つでしょう。また、EPFLがその開発およびリリースプロセスを改善するうえでどの程度の成功を収めているかについてもお待ちしています。私が見ているものは希望的に見えますが、私は保守的な会社で働いています。

「Scalaは主流の開発者にとっては複雑すぎるのか」というより一般的なトピックの1つ...

主流を問わず、ほとんどの開発者は既存のシステムを維持または拡張しています。これは、彼らが使用していることのほとんどが、ずっと前に行われた決定によって決定されることを意味します。 COBOLを書いている人はまだたくさんいます。

明日の主流開発者は、今日構築されているアプリケーションの保守と拡張に取り組みます。これらのアプリケーションの多くは、主流の開発者によって構築されていません。明日の主流開発者は、今日最も成功している新しいアプリケーションの開発者によって使用されている言語を使用するでしょう。

55
Erik Engbrecht

ScalaコミュニティがScalaに不慣れなプログラマの恐れを和らげるのを助けることができる1つの方法は練習に集中して、例によって教えることです - 小さく始めて徐々に大きくなる多くの例。これがこのアプローチをとる少数のサイトです:

これらのサイトにしばらく時間をかけた後、Scalaとそのライブラリーは、おそらく設計と実装が難しいものの、特に一般的なケースではそれほど難しいものではないことがすぐにわかります。

46
Derek Mahar

私は安い "大衆市場"の米国の大学で学士号を取得しているので、私はユーザーインテリジェンス(または少なくとも教育)規模の真ん中に陥ると思います:)私はほんの数ヶ月間Scalaに手を出していますそして2つか3つの重要でないアプリに取り組んできました。

特にIntelliJが彼らの素晴らしいIDEをリリースしたので、IMHOが現在最も優れたScalaプラグインであることを考えれば、Scalaの開発は比較的簡単です。

  • 私はScalaを "セミコロンなしのJava"として使うことができると思います。すなわち、私はJavaですることと同じように見えるコードを書くことができ、型推論によって得られるような構文の簡潔さから少し恩恵を受けます。例外処理は、やるともっと便利です。クラス定義は、ゲッター/セッターの定型句がない限り、冗長度がはるかに低くなります。

  • たまには、1行でJavaの複数行に相当する行を書くことができます。該当する場合、map、fold、collect、filterなどの一連の機能的な方法は、作成するのが楽しく、見やすくエレガントです。

  • Scalaのより強力な機能、つまりクロージャーや部分的な(あるいはカリー化された)機能、パターンマッチングなどが、私自身の利益になることはめったにありません。

初心者として、私は簡潔で慣用的な構文に苦しみ続けています。パラメータなしのメソッド呼び出しでは、必要な場合を除いて括弧は不要です。 match文の中では太い矢印(=>)が必要な場合がありますが、細い矢印(->)が必要な場所もあります。多くのメソッドは/:\:のように短くてややわかりにくい名前を持っています - 十分なマニュアルページをめくれば私の作業は完了しますが、コードの中にはPerlやラインノイズのように見えるものがあります。皮肉なことに、構文上の省略形の最も一般的な部分の1つが欠けています。Int++メソッドを定義していないという事実に噛み付かれ続けています。

これは私の意見です。ScalaはC++の力とC++の複雑さと読みやすさを兼ね備えていると私は思います。言語の構文上の複雑さもAPIドキュメントを読みにくくします。

Scalaは非常によくよく考え抜かれて、多くの点で素晴​​らしいです。私は多くの学者がそれをプログラムするのを好むだろうと思います。しかし、それはまた巧妙さと落とし穴でいっぱいです、それはJavaよりはるかに高い学習曲線を持ち、読むのがより難しいです。フォーラムをスキャンして、まだJavaの細かい点に苦しんでいる開発者が何人いるのかを見てみるとScalaが主流の言語になることは想像できません。以前は1週間のJavaコースしか必要なかった3週間のScalaコースで開発者を送ることを正当化することはできません。

41
Carl Smotricz

その方法の主な問題は、(implicit bf : CanBuildFrom[Repr, B, That])が何の説明もないことです。どんな暗黙の引数であるかはわかっていますが、これが呼び出しにどのように影響するかを示すものは何もありません。 scaladocを追いかけても私は混乱するだけです(CanBuildFromname__に関連するクラスのいくつかはドキュメンテーションさえ持っていません)。

単純な「bfname__のスコープ内に、Bname__型のオブジェクトのビルダーとして戻り型Thatname__を作成するための暗黙的なオブジェクトが存在しなければならない」というのはいくらか役に立ちますが、実際に必要なのはmapです。 Aname__からBname__へ。実際、私はReprname__型が何を意味するのかわからないし、Traversablename__のドキュメントにはまったく手がかりがないので、そのことが正しいかどうかわかりません。

それで、私は2つの選択肢を残しました、それらのどちらも楽しいです:

  • 古いマップがどのように機能し、他のほとんどの言語でマップがどのように機能するかが正しく機能すると仮定します。
  • ソースコードをさらに詳しく調べる

私は、Scalaが本質的にこれらのことがどのように機能するかについての本質を明らかにしており、そして最終的にこれがoxbow_lakesが説明していることをする方法を提供することを提供します。しかしそれは署名の気を散らすものです。

32
davetron5000

私はScalaの初心者なので、その型シグネチャに問題があるとは思わない。 parameterはマップする関数であり、暗黙のパラメータは正しいコレクションを返すためのビルダーです。明確で読みやすい。

全体として、実にエレガントです。暗黙のパラメータメカニズムがクラスユーザからこの追加のパラメータを隠している間、ビルダー型パラメータはコンパイラに正しい戻り型を選択させます。私はこれを試しました:

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")

それは多態性です。

今は当然のことながら、これは主流のパラダイムではなく、多くの人々を怖がらせるでしょう。しかし、それはまたその表現力と優雅さを重視する多くの人を引き付けるでしょう。

22
Thomas Heywood

残念ながら、あなたが与えたmapの署名はmapの間違った署名であり、確かに正当な批判があります。

最初の批判は、地図の署名を覆すことによって、もっと一般的なものがあるということです。これがデフォルトで美徳であると信じるのは一般的な誤りです。そうではありません。写像関数は、構成と恒等式の2つの法則を順守して、共変関数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 Functorを介してトラバースを実行することでマップを取得できます)。しかし、私は、ライブラリの作家がよく文書化されているライブラリの一般化を意識しているならば(前述の前にApplicative Programming with Effects)、このエラーは見られないだろうと思う。

第二に、map関数はfor-内包で使われているのでScalaでは特別な場合です。残念ながら、これは、装備の整ったライブラリ設計者が、内包表記の構文上の糖分を犠牲にすることなくこのエラーを無視できないことを意味します。言い換えれば、Scalaライブラリの設計者がメソッドを破棄するのであれば、これは簡単に無視されますが、マッピングしないでください。

誰かがそれについて話してくれることを願っています。それがそのままでは、Scalaが主張しているエラーを回避するのが難しくなるためです。すなわち、「普通のプログラマーからの無責任な異議申し立て(すなわち、難しい!)」の解決策は、「彼らを容易にするために彼らを訴えさせる」ことではなく、むしろより良いプログラマーになるための指針と支援を提供することである。私自身とScalaの目的はこの問題について矛盾していますが、あなたの主張に戻ってください。

あなたはおそらく「平均的なプログラマー」からの具体的な回答を予測してあなたの主張をしていました。つまり、「しかしそれは複雑すぎます」と主張する人たちです。またはいくつかのような。これらはあなたが参照するYeggesまたはBlochです。反知的主義/実用主義運動のこれらの人々への私の反応はかなり過酷であり、私はすでに反応の弾幕を予想しているので、私はそれを省略する。

私は本当にScalaライブラリが改善されることを願っている、あるいは少なくとも、エラーが安全に片隅に隠れることができる。 Javaは、「何でも役に立つことをやろうとする」ことは非常に費用がかかる言語であり、圧倒的な量のエラーを避けることができないため、多くの場合価値がありません。私はScalaに同じ道をたどらないように懇願します。

20
Tony Morris

私は質問とMartinの答えの両方に完全に同意します:)。 Javaでも、ジェネリックを使ってjavadocを読むのは、余分なノイズが原因であるはずの場合よりもはるかに困難です。暗黙のパラメータが質問のサンプルコードのように使われているScalaではこれが複雑になっています(暗黙のうちに非常に有用なコレクションモーフィングのものをしていますが)。

私はそれが言語自体の問題であるとは思わない - 私はそれがもっとツーリングの問題だと思う。そして私はJörgW Mittagが言っていることに同意しますが、scaladoc(あるいはIDEの型のドキュメント)を見ていると思います - メソッドが何であるか、そして何が戻ってくるのかを理解するためにできる限り少ない頭脳力が必要です。それを取得するために紙の上に代数のハックをする必要はないはずです:)

確かにIDEには、任意の変数/ expression/typeのすべてのメソッドを表示するためのNiceメソッドが必要です(Martinの例と同様に、すべての総称をインライン化できるので、Niceで読みやすくなっています)。暗黙のうちに暗黙のうちに隠すというマーティンの考えも好きです。

例をscaladocで取るには...

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

これをscaladocで見るとき、私は一般的なブロック[B、That]を暗黙のパラメータと同様にデフォルトで隠すことを望みます(多分それらはあなたがマウスで小さなアイコンの上に置くと表示されます)それを読むことは、通常それほど関係がありません。例えばこれがこんな感じだったら…….

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

それが何をしているのかはっきりしていてわかりやすい。マウスカーソルを合わせるかクリックすると、たとえば[That]をハイライト表示した[B、That]というテキストが展開される可能性があります。

[]宣言と(暗黙的な...)ブロックに小さなアイコンを使用することもできるかもしれません。トークンを使用するのは難しいですが、私は使用します。今のところ...

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のように宣言してみましょう。ジェネリック型の共変型と反変型は、ノイズを多く追加するため、ユーザーにはわかりやすく表現することができます。

15
James Strachan

私はあなたにそれを破る方法を知りません、しかし私はケンブリッジからの博士号を持っています、そして私はちょうど2.8を使っています。

もっと真剣に、私は2.7を使って時間を過ごすことはほとんどなく(私が使っているJavaライブラリと相互運用することはありません)、Scalaを使い始めたのは一ヶ月ほど前です。私はHaskellである程度の経験を持っていますが(大したことではありませんが)、心配していることを無視して、私のJava(私が生活のために使っている)の経験と一致するメソッドを探しました。

だから:私は「新しいユーザー」であり、私は延期されませんでした - それがJavaのように機能するという事実は私が理解できなかった部分を無視するのに十分な自信を与えました。

(しかし、私がScalaを見た理由は、それを仕事でプッシュするかどうかを確認するためのものだったため、まだそれを行うつもりはありません。私が言っていることは、限られたリソースがそれを理解するために投入されることを望んでいるということです。最終的な州 - 彼らが近いうちにこの人気者になることを期待していたとは思わない。)

11
andrew cooke

Scalaについてはまったく知りませんが、数週間前にはClojureを読むことができませんでした。今、私はそれのほとんどを読むことができますが、最も単純化されたを超えてまだ何も書くことができません。私はScalaに違いはないと思います。あなたが学ぶ方法に応じてあなたは良い本やコースが必要です。上記のmap宣言を読むだけで、多分1/3になります。

より大きな問題はこれらの言語の構文ではなく、日常のプロダクションコードでそれらを使えるようにするパラダイムを採用し、内部化することであると私は思います。私にとって、JavaはC++からの大きな飛躍ではなく、Cからの飛躍でもPascalからの飛躍でもなく、Basicなどでもありませんでした。しかしClojure(とにかく私にとっては)大きな飛躍です。 Scalaでは、JavaスタイルまたはScalaスタイルでコーディングできると思います。しかし、Clojureでは、あなたは避けられない習慣をJavaから守ろうとして、かなりの混乱を引き起こすでしょう。

10
Jeff G

Scalaには非常に複雑で学術的に見えるクレイジーな機能(特に暗黙のパラメータが関係する場合)がたくさんありますが、物事を使いやすくするように設計されています。最も有用なものは構文糖([A <% B]のように、タイプAのオブジェクトがタイプBのオブジェクトへの暗黙の変換を持つことを意味します)とそれらが何をするかについてのよく文書化された説明を得ます。しかし、ほとんどの場合、これらのライブラリのクライアントとして、暗黙のパラメータを無視して、正しいことをするようにそれらを信頼することができます。

7
Ken Bloom

これで人々がScalaにやってくるのをやめるのでしょうか。

Scalaは強力になり、その構文はHaskell、OCaml、SML、LispsのようにJava/C++/PHPプログラマーにとって異質ではないので、Scalaが普及する度合いに影響を与える主な要因ではないと思います。等..

しかし、私はScalaの人気が今日のJavaの水準を下回って横ばいになると思います。また、次の主流言語はもっと単純化しなければならないと思います。 。しかし、私はそのような言語を開発しているので偏りがありますが、私は数か月にわたる研究を除外した後にScalaが私が必要としているものに対して十分ではなかったことをしただけです。

これはScalaに、献身的な博士課程の学生しか理解できない学術的な娯楽として商業的世界では悪い名前を付けることになるでしょうか? CTOやソフトウェアの責任者たちは怖がるのでしょうか。

私はScalaの評判がHaskell複合体から影響を受けるとは思わない。しかし、ほとんどのプログラマーにとって、まだScalaを使わざるを得ないユースケースがまだ見当たらず、それについて学ぶのが先延ばしになるためです。おそらく、非常にスケーラブルなサーバーサイドが最も魅力的なユースケースです。

そして、主流の市場にとっては、最初にScalaを学ぶことは、最初にHTMLやPythonを使用するなど、すぐにプログラムを書くという「新鮮な空気の息吹」ではありません。最初からつまずくすべての詳細を学んだ後、Scalaはあなたに成長する傾向があります。しかし、最初からScalaでのプログラミングを読んでいたとしたら、私の学習曲線に関する経験と意見は異なっていたでしょう。

図書館は賢明なアイデアを再設計しましたか?

絶対に。

あなたがScalaを商業的に使っているなら、あなたはこれを心配していますか?あなたはすぐに2.8を採用する予定ですか、それとも何が起こるのを待つことを予定していますか?

私は私の新しい言語の最初のプラットフォームとしてScalaを使っています。 Scalaを商業的に使用しているのであれば、おそらくScalaのコレクションライブラリでコードを構築することはないでしょう。 Scalazの型シグネチャはScalaのコレクションライブラリよりも冗長で扱いにくいことがわかりました。その問題の一部はおそらくScalaが型クラスを実装する方法であり、それは私が私自身の言語を作成している小さな理由です。


この答えを書くことにしたのは、Scalaのコレクションクラスの設計を自分の言語で行っているものと比較して比較したいと思ったからです。私の思考プロセスも共有するかもしれません。

2.8 Scalaコレクションのビルダー抽象化の使用は、堅実な設計原則です。以下に2つの設計上のトレードオフを検討します。

  1. 書き込み専用コード:このセクションを書いた後、 Carl Smotriczのコメント を読みます。これは、トレードオフになると思われることと一致します。 James Strachanとdavetron 5000のコメントは、Thatの意味(That [B]でもない)と暗黙のメカニズムは直感的に把握するのは容易ではないと同意しています。下記の問題#2で私がモノイドを使用しているのを見てください。 Derek MaharのコメントはScalaを書くことについてのものですが、他の人のScalaを読むことについてのものは「一般的な場合」ではありません。

    私がScalaについて読んだ1つの批判は、他の人が書いたコードを読むよりもそれを書く方が簡単だということです。そして、私はこれがさまざまな理由(例えば関数を書くための多くの方法、自動クロージャ、DSLのためのユニットなど)のために時々本当であると思います、しかしこれが主な要因であるかどうか私は未定です。ここでは、暗黙の関数パラメータの使用に長所と短所があります。プラス面では、それは冗長性を減らし、ビルダーオブジェクトの選択を自動化します。 Oderskyの example では、BitSet、つまりSet [Int]からSet [String]への変換は暗黙的です。コードの不慣れな読者は、現在のパッケージスコープに存在する可能性のあるすべての潜在的な目に見えない暗黙的なビルダー候補について十分に推論することができない限り、コレクションの種類が何であるかを容易に知ることはできません。もちろん、経験豊富なプログラマーとコードの作成者は、BitSetがIntに制限されていることを知っているはずです。したがって、Stringへのマップは別のコレクション型に変換する必要があります。しかし、どのコレクションタイプ?明示的に指定されていません。

  2. アドホックコレクションデザイン:このセクションを書いた後、 Tony Morrisのコメント を読み、私はほぼ同じことを言っていることに気づきました。おそらく私のより冗長な説明は、その点をより明確にするでしょう。

    "型とのビット腐敗の戦い" Odersky&Moorsでは、2つのユースケースが提示されています。これらは、Int要素へのBitSet、およびTuple要素へのMapへのMapの制限であり、一般的な要素マッピング関数A => Bが代替の宛先コレクション型を構築できなければならない理由として提供されています。ただし、これはカテゴリ理論の観点からは欠点があります。カテゴリ理論の一貫性を保ち、ひいてはコーナーケースを回避するために、これらのコレクション型はファンクタです。各モフォミズムA => Bは、同じファンクタカテゴリ内のオブジェクト間でマッピングする必要があります、List [A] => List [B]、BitSet [A] => BitSet [B]。たとえば、Optionは1つのSome(オブジェクト)とNoneのセットの集合として表示できるファンクタです。 OptionのNoneやListのNilから "空"の状態を持たない他の関数への一般的なマップはありません。

    ここではトレードオフ設計の選択があります。私の新しい言語のコレクションコレクションライブラリでは、すべてをファンクタにすることを選択しました。つまり、BitSetを実装する場合は、非ビットフィールドの内部表現を使用してすべての要素型をサポートする必要があります。整数型パラメータであり、その機能はすでにScalaの継承元のSetにあります。そして私のデザインのMapはその値だけをマップする必要があります、そしてそれはその(キー、値)ペアタプルをマップするための別のnon-functorメソッドを提供することができます。 1つの利点は、各ファンクターが通常は適用対象であり、おそらくモナドでもあることです。したがって、要素型間のすべての機能、たとえばA => B => C => D => ...は、持ち上げられたアプリケーションタイプの間の関数に自動的に持ち上げられます。 List [A] => List [B] => List [C] => List [D] => ....ファンクタから他のコレクションクラスへの写像のために、私はモノイドをとる写像オーバーロードを提供します。 Nil、None、0、 ""、Array()など。したがって、ビルダー抽象化関数はモノイドのappendメソッドであり、必要な入力パラメーターとして明示的に提供されるため、暗黙的な変換は表示されません。 (Tangent:この入力パラメータは、Scalaのマップデザインではできない、空でないモノイドへの追加も可能にします。)そのような変換は、同じ繰り返しパスにおけるマップとフォールドです。また、カテゴリの意味で、「すべてのコレクションクラスが両方である」任意のトラバース可能なオブジェクトから任意のトラバース可能なオブジェクトへの1回の繰り返しパスでmap + foldを有効にする、トラバース可能な「効果を伴うアプリケーションプログラミング」McBride&Pattersonも提供します。また、州モナドは応用的であり、したがってあらゆるトラバース可能性からの完全に一般化されたビルダー抽象化です。

    つまり、Scalaのコレクションは、カテゴリ理論に根ざしていないという意味で「アドホック」であり、カテゴリ理論はより高水準の表示的セマンティクスの本質です。 Scalaの暗黙のビルダーは、最初はファンクターモデル+モノイドビルダー+トラバース - > Applicativeよりも "より一般化されている"ように見えますが、どのカテゴリーとも整合性があるとは証明されていません。最も一般的な意味と、どのようなコーナーケースが与えられるかは、どのカテゴリモデルにも従わない可能性があります。もっと多くの変数を追加することで何かがより一般的になることは事実ではありません。これはカテゴリ理論の大きな利点の1つでした。それはより高いレベルのセマンティクスに持ち上げながら一般性を維持する規則を提供するということです。コレクションはカテゴリです。

    私がどこかで読んだ、私はそれがライブラリデザインのもう一つの正当化としてOderskyであったと思う、純粋な機能的スタイルでのプログラミングは限られた再帰と末尾再帰が使われないスピードのコストがあるということです。私がこれまでに遭遇したすべてのケースで末尾再帰を採用することが難しいとは思いませんでした。


加えて、私は頭の中で、Scalaのトレードオフのいくつかは、例えばHaskellや私が開発している言語とは違って、可変と不変の両方の言語になろうとしていることによるものであるという不完全な考えを思い出します。これは内包についてのTony Morrisのコメントと一致しています。私の言語では、ループも可変構造もありません。私の言語は(現時点では)Scalaの上に置かれるでしょう、そしてそれに多くを負っています、そしてScalaが一般的な型システムと可変性を持っていなかったならばこれは不可能でしょう。私はOdersky&Moors( "型とのビット腐敗の戦い")はScalaが高級言語を持つ唯一のOOP言語であると述べるのは間違っていると思うので、それは本当ではないかもしれません。 Bob Harperによると、Standard MLはそれらを持っています。また、SMLの型システムは(1980年代以降)同等に柔軟である可能性がありますが、構文はScalaほどJava(およびC++/PHP)とそれほど似ていないため、容易には理解できません。いずれにせよ、これはScalaに対する批判ではなく、むしろトレードオフの不完全な分析を提示しようとする試みであり、それは私が質問に密接に関係していることを私は願っています。 ScalaとSMLはHaskellが diamond multiple inheritance を実行できないことに悩まされることはありません。 。

6

ここで学位を述べる必要があるようです。政治学の学士号およびコンピューター科学の学士号を取得。

ポイントへ:

これで人々がScalaにやってくるのをやめるのでしょうか。

その根底にあるプログラミングパラダイムが難しいので、Scalaは難しいです。関数型プログラミングは多くの人を怖がらせます。 PHPでクロージャを構築することは可能ですが、そうすることはめったにありません。そのため、基本的なパラダイムの力を評価するための特別な教育を受けていないのであれば、そうではありません。

この教育が利用可能であるならば、誰でもそれをすることができます。昨年、私はSCALAでたくさんの学校の子供たちと一緒にチェスコンピューターを作りました!彼らは問題を抱えていましたが、結局はうまくいきました。

あなたがScalaを商業的に使っているなら、あなたはこれを心配していますか?あなたはすぐに2.8を採用する予定ですか、それとも何が起こるのを待つことを予定していますか?

私は心配しないでしょう。

5
Julian Dehne

オックスフォードの数学の学位も持っています。新しいコレクションのものを「入手」するのにしばらく時間がかかりました。しかし、私は今それが大好きです。実際、 'map'の型付けは2.7で私を悩ませた最初の大きなことの1つでした(おそらく私が最初に行ったのはコレクションクラスのサブクラスの1つだったので)。

新しい2.8コレクションに関するMartinの論文を読むことは暗黙の使用の説明に本当に役立ちました、しかし確かにドキュメンテーション自体はコアAPIのメソッドシグネチャの中の異なる種類の暗黙の役割を説明するより良い仕事をする必要があります。

私の主な関心事はもっとこれです:2.8がいつリリースされるのですか?バグ報告がいつ届かなくなるのでしょうか。 Scalaチームは2.8で噛むことができる以上に噛み付いたことがありますか。

私は2.8以外のものを追加する前に2.8がリリース用に安定化されていることを本当に望んでいますし、scalaコンパイラの開発ロードマップを管理する方法に何らかの改善ができるかどうか疑問に思います。

4
Matt