875

差し迫った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 が Java になることは確かに実現可能であると思います。次の Ruby または Python (つまり、重要な商用ユーザー ベースを獲得するため)

  • これは、人々が Scala に来るのを遠ざけるのでしょうか?
  • これは、熱心な博士課程の学生だけが理解できるアカデミックな遊び道具として、商用の世界で Scala に悪い評判を与えることになるのでしょうか? CTOやソフトウェアの責任者は怖がるでしょうか?
  • ライブラリの再設計は賢明なアイデアでしたか?
  • Scala を商業的に使用している場合、これについて心配していますか? 2.8 をすぐに採用する予定ですか、それとも何が起こるかを待つ予定ですか?

Steve Yegge はかつて Scala を攻撃しました (私の意見では間違っていました)。誰かがこの API を使ってFUDを広めるフィールド デイを開催するのではないかと心配しています (Josh Blochが Java にクロージャを追加することからJCPを怖がらせたのと同様に)。

-ジョシュア ブロッホが BGGA 閉鎖提案の却下に影響を与えたと私は信じていますが、これは提案が誤りであるという彼の正直な信念以外の何物でもないことを明確にしておく必要があります。


妻や同僚が何を言おうと、私は馬鹿だとは思いません: 私はオックスフォード大学で数学の学位を取得しており、ほぼ 12 年間商用プログラミングを行っており、Scalaで約 1年間プログラミングを行ってきました。年間(商業的にも)。

扇動的な件名は、1980 年代初頭の英国の政党のマニフェストについての引用であることに注意してください。この質問は主観的なものですが、本物の質問です。私はそれを CW にしました。この件について意見をお願いします。

4

18 に答える 18

892

「遺書」ではないことを願っていますが、あなたの言いたいことはわかります。Scala の長所であると同時に問題でもあるもの、つまりその拡張性に気付きました。これにより、ほとんどの主要な機能をライブラリに実装できます。他のいくつかの言語では、maporのようなシーケンスcollectが組み込まれており、それらをスムーズに動作させるためにコンパイラーが通過しなければならないすべてのフープを誰も見る必要はありません。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 をs にマッピングすると、Int再び a が得られますが、 s をs にBitSetマッピングすると、一般的な が得られます。map の結果の静的な型と実行時の表現は、渡される関数の結果の型に依存します。これはセットが空の場合でも機能するため、関数は適用されません! 私の知る限り、同等の機能を持つコレクション フレームワークは他にありません。しかし、ユーザーの観点からは、これが機能するはずの方法です。IntStringSet

私たちが抱えている問題は、これを実現するすべての巧妙なテクノロジーが型シグネチャに漏れ込み、大きくて恐ろしいものになることです。mapしかし、おそらくユーザーはデフォルトで?の完全な型シグネチャを表示されるべきではありません。彼女mapが見上げたらどうですか?BitSet

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

ユーザーの観点からは実際に map のタイプが(Int => Int) => BitSet. ただしmap、別のリンクをクリックして検査できる、より一般的なタイプもあります。

このような機能はまだツールに実装していません。しかし、人々を怖がらせず、より有用な情報を提供するために、これを行う必要があると私は信じています. そのようなツールがあれば、スマート フレームワークやライブラリが遺書にならないように願っています。

于 2009-11-13T09:28:46.170 に答える
226

私は博士号も、CSでも数学でも、他の分野でも、他の種類の学位は持っていません。私はScalaや他の同様の言語の経験がありません。私は、リモートで比較可能な型システムでさえ経験がありません。実際、私が持っている唯一の言語は、型システムさえも持っている表面的な知識以上のものであり、その洗練された型システムで正確に知られているわけではありません。(範囲タイプはありますが、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

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

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

私が本当に信じていることは、それほど理解するのは難しいことではありません。本当に必要な知的ツールは2つだけです。

  1. あなたは(大まかに)何であるかを知る必要がありmapます。メソッドの名前なしで型アノテーションのみを指定した場合、何が起こっているのかを理解するのは非常に困難になることを認めます。しかし、何をすべきかをすでに知っていて、その型シグネチャが何でmapあるかを知っているので、シグネチャをすばやくスキャンして、「なぜこれmapは1つではなく2つの関数を引数として取るのか」などの異常に焦点を当てることができます。
  2. 型アノテーションを実際に読み取ることができる必要があります。しかし、Scalaをこれまでに見たことがない場合でも、これは非常に簡単なはずです。これは、他の言語ですでに知っている型構文の混合物にすぎないためです。VB.NETは、パラメトリックポリモーフィズムに角括弧を使用し、矢印を使用してタイプを返し、名前とタイプを区切るコロンは、実際には標準です。
  3. ジェネリックプログラミングとは何かを大まかに知る必要があります。(これは基本的にすべて名前で綴られているので、理解するのはそれほど難しいことではありません。文字通り、一般的な方法でプログラミングしているだけです)

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

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

于 2009-11-12T18:56:31.527 に答える
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;
}
于 2010-03-29T22:07:32.900 に答える
71

そうですね、あなたの痛みは理解できますが、率直に言って、あなたや私のような人、または通常のスタック オーバーフロー ユーザーのほとんどはルールではありません。

私が言いたいのは、ほとんどのプログラマーは型シグネチャを気にしないということです。彼らはドキュメントを読みません。

コードがどのように機能するかの例を見て、コードが期待する結果を生成するのに失敗しない限り、彼らはドキュメントを見ません。それが失敗した場合、彼らはドキュメントを見て、上部に使用例が表示されることを期待します。

これらを踏まえて、私は次のように考えています。

  1. その型シグネチャに出くわした人は誰でも (ほとんどの人がそうであるように)、Scala に反対する傾向がある場合は Scala を際限なく嘲笑し、Scala が好きな場合はそれを Scala の力の象徴と見なします。

  2. ドキュメントが使用例を提供し、メソッドの目的と使用方法を明確に説明するように強化されていない場合、Scala の採用を少し損なう可能性があります。

  3. 長期的には、それは問題ではありません。Scala がそのようなことを実行できるということは、Scala 用に作成されたライブラリーをより強力で安全に使用できるようにすることです。これらのライブラリとフレームワークは、強力なツールに惹きつけられるプログラマーを引き付けます。

  4. シンプルさと直接性を好むプログラマーは、引き続き PHP や類似の言語を使用するでしょう。

悲しいかな、Java プログラマーは強力なツールに夢中になっているので、それに答えて、メインストリームの Scala 採用に対する私の予想を修正しました。Scala が主流の言語になることはまったく疑いの余地がありません。C のメインストリームではなく、おそらく Perl のメインストリームまたは PHP のメインストリームです。

Java といえば、クラスローダーを置き換えたことはありますか? それが何を含んでいるのかを調べたことがありますか?フレームワークの作成者が行っている場所を見ると、Java は恐ろしいものになる可能性があります。ただ、ほとんどの人はそうではありません。同じことが Scala にも当てはまりますが、私見ですが、アーリー アダプターは、遭遇する岩の下を調べて、そこに何かが隠れているかどうかを確認する傾向があります。

于 2009-11-12T20:39:48.060 に答える
55

これは人々がScalaに来るのを先延ばしにするだろうか?

はい、しかしそれはまた人々が延期されるのを防ぎます。Scalaがより高い種類のタイプのサポートを獲得して以来、より高い種類のタイプを使用するコレクションの欠如が大きな弱点であると私は考えてきました。APIドキュメントがより複雑になりますが、実際には使用法がより自然になります。

これは、熱心な博士課程の学生だけが理解できる学術的なおもちゃとして、商業の世界でscalaに悪い名前を付けることになるのでしょうか?CTOとソフトウェアの責任者は怖がりますか?

おそらくそうする人もいます。Scalaの複雑さや、多くの開発者が学びたがらないこともあり、多くの「プロの」開発者がScalaにアクセスできるとは思いません。そのような開発者を雇用しているCTOは当然怖がります。

ライブラリは賢明なアイデアを再設計しましたか?

絶対。それはまだいくつかの荒削りな部分があるとしても、コレクションを他の言語や型システムとはるかによく適合させます。

Scalaを商業的に使用している場合、これについて心配していますか?2.8をすぐに採用する予定ですか、それとも何が起こるかを待つ予定ですか?

私はそれを商業的に使用していません。バグを洗い流すことができるように、2.8.xシリーズを導入しようとする前に、少なくとも2、3回転するまで待つでしょう。また、EPFLがリリースプロセスの開発を改善する上でどれほどの成功を収めているかを見るのを待ちます。私が見ているものは希望に満ちているように見えますが、私は保守的な会社で働いています。

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

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

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

于 2009-11-12T17:28:10.300 に答える
46

ScalaコミュニティがScalaを初めて使用するプログラマーの恐怖を和らげるのに役立つ方法のひとつは、練習に集中し、例を挙げて教えることです。多くの例は、小さく始まり、徐々に大きくなります。このアプローチを採用しているサイトは次のとおりです。

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

于 2009-11-15T11:08:51.417 に答える
33

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

bf単純な「型のオブジェクトのビルダーをB戻り値の型に提供する暗黙的なオブジェクトがスコープ内に存在する必要がありますThat」が多少役立つと思いますが、本当にやりたいのは mapAの toBの。実際、型が何を意味するのかわからないため、それが正しいかどうかはわかりませんRepr。また、ドキュメントにTraversableはまったく手がかりがありません。

したがって、私には 2 つのオプションが残されていますが、どちらも快適ではありません。

  • 古いマップがどのように機能し、他のほとんどの言語でマップがどのように機能するかがうまくいくと仮定します
  • ソースコードをもう少し掘り下げます

Scala は基本的に、これらがどのように機能するかの内臓を公開しており、最終的には oxbow_lakes が記述していることを実行する方法を提供していると理解しています。しかし、それは署名の気晴らしです。

于 2009-11-23T03:22:55.767 に答える
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")

それは正しく行われたポリモーフィズムです。

確かに、これは主流のパラダイムではなく、多くの人を怖がらせるでしょう。しかし、その表現力と優雅さを高く評価する多くの人を魅了します。

于 2010-03-29T02:01:14.277 に答える
20

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

最初の批判は、マップの署名を覆すことによって、より一般的なものを手に入れたことです。これがデフォルトで美徳であると信じるのはよくある誤りです。そうではありません。写像関数は、共変関手 Fx -> (x -> y) -> Fy として非常によく定義されており、合成と恒等の 2 つの法則を順守しています。「地図」に起因する他のものはすべて茶番です。

指定された署名は別のものですが、マップではありません。私がそうしようとしていると思われるのは、紙の「トラバース」署名の特殊化されたわずかに変更されたバージョン、イテレーターパターンの本質です。その署名は次のとおりです。

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 ファンクターを介してトラバースを実行することでマップを取得できることに注意してください)。しかし、ライブラリの作成者が、十分に文書化されたライブラリの一般化にもっと気づいていれば (効果を伴う応用プログラミングが前述のものより先行しています)、このエラーは表示されないのではないかと思います。

第 2 に、map 関数は for 内包表記で使用されるため、Scala では特殊なケースです。残念ながら、これは、より優れた設備を備えたライブラリ設計者が、理解の構文糖衣を犠牲にすることなく、このエラーを無視できないことを意味します。言い換えれば、Scala ライブラリの設計者がメソッドを破棄した場合、これは簡単に無視されますが、マッピングしないでください!

誰かがそれについて声を上げてくれることを願っています。なぜなら、このままでは Scala が主張するエラーを回避することが難しくなるからです。これには明らかに私が強く反対する理由があります。つまり、「平均的なプログラマーからの無責任な反対意見 (つまり難しすぎる!)」に対する解決策は、「彼らをなだめてやりやすくする」ことではなく、より優れたプログラマーになるための指針と支援を提供することです。私自身と Scala の目的は、この問題について争っていますが、あなたの主張に戻ります。

あなたはおそらく、「平均的なプログラマー」からの特定の反応を予測して、自分の主張をしていたのでしょう。つまり、「でも複雑すぎる!」と主張する人たちです。またはそのようなもの。これらは、あなたが参照する Yegges または Blochs です。反知性主義/プラグマティズム運動のこれらの人々に対する私の反応は非常に厳しく、私はすでに反応の弾幕を予想しているので、それを省略します.

Scala ライブラリが改善されることを心から願っています。少なくとも、エラーが隅に安全に隠されていることを願っています。Java は、「何か役に立つことをしようとする」ことが信じられないほどコストがかかる言語であり、圧倒的な量のエラーを単純に回避できないため、その価値がないことがよくあります。私は Scala が同じ道をたどらないように懇願します。

于 2009-11-14T21:34:47.663 に答える
15

私は質問とマーティンの答えの両方に完全に同意します:)。Java であっても、ジェネリックを使用して javadoc を読み取ることは、余分なノイズが原因で本来よりもはるかに困難です。これは、質問のコード例のように暗黙のパラメーターが使用される Scala で複合化されます (暗黙のパラメーターは非常に便利なコレクションのモーフィングを行います)。

言語自体の問題ではないと思います。ツールの問題だと思います。そして、Jörg W Mittag の言うことには同意しますが、scaladoc (または IDE の型のドキュメント) を見ると、メソッドとは何か、それが何を取り、何を返すかを理解するのに、できるだけ頭脳の力を必要としないはずです。それを得るために、ちょっとした紙の上でちょっとした代数をハックする必要はないはずです:)

確かに、IDE には、任意の変数/式/型のすべてのメソッドを表示する優れた方法が必要です (Martin の例のように、すべてのジェネリックをインライン化できるため、簡単に理解できます)。デフォルトでインプリシットを非表示にするという Martin のアイデアも気に入っています。

scaladoc で例を挙げると...

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

これを scaladoc で見ると、一般的なブロック [B, That] と暗黙のパラメーター (マウスで小さなアイコンをホバーすると表示される可能性があります) をデフォルトで非表示にしたいと思います - grok への余分なものとして通常はそれほど関係のないものを読んでください。たとえば、これが次のように見えると想像してください...

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

それが何をするかは素晴らしく、明確で明白です。'That' とは何か疑問に思われるかもしれません。マウス オーバーまたはクリックすると、[B, That] テキストが展開され、たとえば '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 にカーソルを合わせると、A1 が A1 <: A. であるという宣言を示すことができます。ジェネリックの共変型と反変型は多くのノイズを追加し、ユーザーにとってはるかに簡単に理解できる方法でレンダリングできると思います。

于 2010-03-04T10:22:18.380 に答える
11

私はあなたにそれを壊す方法がわかりませんが、私はケンブリッジから博士号を取得しており、2.8をうまく使用しています。

さらに深刻なことに、私は2.7でほとんど時間を費やさず(使用しているJavaライブラリと相互運用しません)、1か月ほど前にScalaを使い始めました。私はHaskellの経験がありますが(あまりありません)、心配していることを無視して、Java(私が生活に使用している)での経験に一致するメソッドを探しました。

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

(ただし、Scalaを検討した理由の一部は、Scalaを機能させるかどうかを確認するためであり、まだそうするつもりはありません。ドキュメントの威圧感を軽減することは確かに役立ちますが、驚いたのは、それがまだどれだけ残っているかです。変更と開発(公平を期すために私が最も驚いたのは、それがどれほど素晴らしいかということでしたが、変更はすぐに来ました)。最終的な状態-彼らがこれほど人気が​​あるとは思っていなかったと思います。)

于 2009-11-12T15:02:14.933 に答える
10

Scala はまったく知りませんが、数週間前に Clojure を読むことができませんでした。今、私はそのほとんどを読むことができますが、最も単純化された以外はまだ何も書くことができません. Scalaも例外ではないと思います。学習方法に応じて、優れた本またはコースが必要です。上記のマップ宣言を読むだけで、おそらく1/3 を取得できます。

より大きな問題は、これらの言語の構文ではなく、日常の製品コードで使用できるようにするパラダイムを採用して内部化することだと思います。私にとって、Java は C++ からの大きな飛躍ではありませんでした。C からの大きな飛躍でもありませんでした。また、Pascal や Basic などからの大きな飛躍でもありませんでした...しかし、Clojure のような関数型言語でのコーディングは大きな飛躍です (とにかく私)。Scala では、Java スタイルまたは Scala スタイルでコーディングできると思います。しかし、Clojure では、命令型の習慣を Java から守ろうとして、かなりの混乱を招くことになります。

于 2010-03-28T19:56:38.527 に答える
7

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

于 2009-11-12T15:02:37.613 に答える
6

これは、人々が Scala に来るのを遠ざけるのでしょうか?

Scala には多くのパワーがあり、その構文は Java/C++/PHP プログラマーにとって Haskell、OCaml、SML、Lips、等..

しかし、Scala の人気は現在の Java よりも低い水準で横ばいになると思います。なぜなら、次の主流言語はもっと単純化されなければならないと私は考えているからです。そこにたどり着く唯一の方法は純粋な不変性、つまり HTML のような宣言型ですが、完全なチューリングです。 . しかし、私はそのような言語を開発しているので偏見がありますが、Scala は私が必要としているものを十分に満たすことができないという数か月にわたる調査を除外した後にのみ開発しました。

これは、熱心な博士課程の学生だけが理解できるアカデミックな遊び道具として、商用の世界で Scala に悪い評判を与えることになるのでしょうか? CTO やソフトウェアの責任者は怖がるでしょうか?

Scala の評判が Haskell コンプレックスによって損なわれるとは思いません。しかし、ほとんどのプログラマーにとって、Scala の使用を強制するユースケースがまだ見当たらず、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 と davetron5000 のコメントは、That の意味 (That[B] でさえない) と暗黙のメカニズムを直感的に把握するのは容易ではないことに同意します。以下の問題#2でのモノイドの使用を参照してください。これははるかに明示的だと思います。Derek Mahar のコメントは Scala を書くことについてですが、「一般的なケース」ではない他の人の Scala を読むことについてはどうでしょうか。

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

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

    「Fighting Bit Rot with Types」では、Odersky & Moors が 2 つのユース ケースを紹介しています。これらは、BitSet から Int 要素への制限、および Map からペアのタプル要素への制限であり、一般的な要素マッピング関数 A => B が別の宛先コレクション型を構築できなければならない理由として提供されています。ただし、これは圏論の観点からは欠陥があります。圏論で一貫性を保ち、コーナー ケースを回避するために、これらのコレクション型はファンクターであり、各モーフィズム A => B は、同じファンクター カテゴリー List[A] => List[B]、BitSet 内のオブジェクト間でマッピングする必要があります。 [A] => ビットセット[B]。たとえば、Option は、1 つの Some( object ) と None のセットのコレクションとして表示できるファンクターです。Option の None や List の Nil から、他の Functor への一般的なマップはありません。

    ここではトレードオフの設計選択があります。私の新しい言語のコレクション ライブラリの設計では、すべてをファンクターにすることを選択しました。つまり、BitSet を実装する場合、すべての要素の型をサポートする必要があります。整数型パラメーターであり、その機能は Scala で継承する Set に既に含まれています。また、私の設計の Map はその値のみをマップする必要があり、(キー、値) ペアのタプルをマップするための別の非ファンクター メソッドを提供できます。利点の 1 つは、通常、各ファンクターがアプリカティブでもあり、おそらくモナドでもあることです。したがって、要素タイプ間のすべての関数、たとえば A => B => C => D => ... は、持ち上げられたアプリケーション タイプ間の関数に自動的に持ち上げられます。たとえば、List[A] => List[B] => List[ C] => リスト[D] => .... ファンクターから別のコレクション クラスへのマッピングのために、Nil、None、0、""、Array() などのモノイドを取るマップ オーバーロードを提供します。必要な入力パラメータとして明示的に提供されるため、目に見えない暗黙の変換はありません。(Tangent: この入力パラメーターは空でないモノイドへの追加も可能にしますが、これは Scala のマップ設計では実行できません。) このような変換は、同じ反復パス内のマップと折り畳みです。また、カテゴリの意味で、「効果のあるアプリカティブ プログラミング」McBride & Patterson を提供します。これは、トラバーサブルからアプリカティブへの単一の反復パスでマップ + フォールドを可能にし、ほとんどすべてのコレクション クラスが両方です。

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

    ライブラリ設計のもう1つの正当化として、Oderskyだったと思いますが、純粋な関数型スタイルでのプログラミングには、再帰が制限され、末尾再帰が使用されない場合の速度が犠牲になるということです。これまでに遭遇したすべてのケースで末尾再帰を採用するのが難しいとは思いませんでした。


さらに、Scala のトレードオフのいくつかは、たとえば Haskell や私が開発している言語とは異なり、変更可能かつ不変の言語になろうとすることが原因であるという不完全な考えを心に留めています。これは、理解のためのトニー・モリスのコメントと一致します。私の言語には、ループも変更可能な構造もありません。私の言語は (今のところ) Scala の上に置かれ、Scala に大きく依存していますが、Scala に一般的な型システムと可変性がなければ、これは不可能です。ただし、それは真実ではないかもしれません.Odersky&Moors(「Fighting Bit Rot with Types」)は、Scalaがより高次の種類を持つ唯一のOOP言語であると述べているのは間違っていると思います。 ML にはそれらがあります。また、SML の型システムは (1980 年代以降) 同等に柔軟である可能性があります。これは、構文が Java (および C++/PHP) と Scala ほど似ていないため、すぐには認識されない可能性があります。いずれにせよ、これは Scala に対する批判ではなく、トレードオフの不完全な分析を提示しようとする試みであり、それが質問に密接に関係していることを願っています。Scala と SML は、Haskell の無能さに悩まされることはありませんダイアモンド多重継承は重要であり、Haskell Prelude の非常に多くの関数がさまざまな型に対して繰り返される理由を理解しています。

于 2011-09-13T05:51:00.417 に答える
4

私もオックスフォードで数学の学位を取得しています!新しいコレクションのものを「入手」するのにしばらく時間がかかりました. でも今はとても気に入っています。実際、'map' の入力は、2.7 で私を悩ませた最初の大きな問題の 1 つでした (おそらく、最初に行ったのがコレクション クラスの 1 つをサブクラス化したためです)。

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

私の主な関心事はこれです: 2.8 はいつリリースされますか? バグレポートが来なくなるのはいつですか? scala チームは 2.8 で噛み砕く以上に食い物にしましたか / 一度にあまりにも多くの変更を試みましたか?

他の新しいものを追加する前に、優先順位として 2.8 の安定版リリースを確認したいと考えています。また、(傍観者として見ながら) scala コンパイラの開発ロードマップの管理方法に何らかの改善を加えることができるかどうか疑問に思っています。

于 2010-03-30T23:54:46.630 に答える
0

利用サイトのエラーメッセージは?

また、既存の型を DSL に適合するカスタム型と統合する必要がある場合はどうなるでしょうか。関連付け、優先順位、暗黙の変換、暗黙のパラメーター、高次の種類、そしておそらく存在型について十分に教育を受ける必要があります。

ほとんどが単純ですが、必ずしも十分ではないことを知っておくことは非常に良いことです。広範囲にわたるライブラリを設計する場合、このことを知っている人が少なくとも 1 人はいるはずです。

于 2010-03-29T11:18:20.493 に答える