2012-03-19 10 views
2

Josh Suereshの新しいマニングの本「Scala in Depth」の第2章はhereです。記事を読んで、私はこのコードのビットに出くわした:"Scala in Depth"で混乱しています。オプションの例

def getTemporaryDirectory(tmpArg : Option[String]) : java.io.File = { 

    tmpArg.map(name => new java.io.File(name)). 

      filter(_.isDirectory). 

     getOrElse(new java.io.File(System.getProperty("java.io.tmpdir"))) 

} 

上記のコードを説明するフォローアップテキストが読み:

getTemporaryDirectory方法は として含有するオプションをコマンドラインパラメータを取ります文字列を返し、使用する一時ディレクトリの を参照するFileオブジェクトを返します。まず、 パラメータがある場合、java.io.Fileを作成するOptionのmapメソッドを として使用します。次に、この新しく作成されたファイルオブジェクト がディレクトリであることを確認します。これを行うには、フィルターメソッドを使用します。これは、Optionの値がある述語に従うかどうかをチェックし、そうでなければ がNoneに変換されるかどうかを確認します。 最後に、 オプションに値があるかどうかを確認します。それ以外の場合は、デフォルトの一時ディレクトリが返されます。

私はJavaから来て、Scalaを学ぶために、コードの構文が私を混乱させます。マップ(...)関数呼び出しの後にドットがどのようにあるのかわかりません。タイプ推論があまりにも多いようですが、どこかで何かが見つからず、タイプが見えません。

スケーラを学んで、すべての推測タイプを見て、すべての削減を取り除く(または適用を解除する)ことができたら、非常に助かります。つまり、Java以前のバージョン6コレクションクラスのequalsの両側で型を明示する必要がありました。

Scalaのコードスニペットをとり、明示的に異なるものを作成するツールがあります(フラグ、タイプ、インプリシット、ブレース、セミコロン)。私は完全に簡潔なコードからJavaに近いものまで私を歩かせるだけのものが必要なので、もっと簡潔なScalaを読んで(そして最終的には書く)自分のスキルを身につけることができると感じることができます。私は、特に上記にこだわってないです

def getTemporaryDirectory(tmpArg : Option[String]) : java.io.File = { 

    ContainerType1[Type1] t1 = tmpArg.map(name => new java.io.File(name)); 
    ContainerType2[Type2] t2 = t1.filter(_.isDirectory); 
    return t2.getOrElse(new java.io.File(System.getProperty("java.io.tmpdir"))); 

} 

:ここ

は、私が探しています何のようなものです。私はちょうど型推論のために何が起こっているのかという点で連鎖関数呼び出しがどのように機能するかを追うことができません。これに関する助けがあれば大いに感謝します。

+0

この記事では、上記のような問題を抱えています。http://zeroturnaround.com/blog/scala-sink-or-swim-part-1/ – chaotic3quilibrium

+3

このレベルでは、 Oderskyらのプログラミングは、SuerethのScalaの深さよりもScalaでプログラミングされています。ただ言って。 –

+1

[この投稿](http://skipoleschris.blogspot.co.uk/2012/03/map-flatten-and-flatmap.html)と素敵なアニメーションは、おそらくあなたにもっと感動を与えるでしょう –

答えて

11

として再記述することができさて、あなたは一つ一つの連鎖のコマンドを試してみて、その結果の種類を確認するにはREPLを持っていますが、私は署名を見てわからないのに役立ちますあなたはそんなに:

scala> Some("c:\\users\\paolo") 
res0: Some[java.lang.String] = Some(c:\users\paolo) 

scala> res0.map(name => new java.io.File(name)) 
res1: Option[java.io.File] = Some(c:\users\paolo) 

scala> res1.filter(_.isDirectory) 
res2: Option[java.io.File] = Some(c:\users\paolo) 

scala> res2.getOrElse(new java.io.File(System.getProperty("java.io.tmpdir"))) 
res3: java.io.File = c:\users\paolo 

ここからもう一度やり直してみましょう。だから、Optionを使用して

scala> None:Option[String] 
res6: Option[String] = None 

scala> res6.map(name => new java.io.File(name)) 
res7: Option[java.io.File] = None 

scala> res7.filter(_.isDirectory) 
res8: Option[java.io.File] = None 

scala> res8.getOrElse(new java.io.File(System.getProperty("java.io.tmpdir"))) 
res9: java.io.File = C:\Users\paolo\AppData\Local\Temp 

は、私たちは、私たちは、おそらくJavaでどうなるようなすべてのステップでヌルをチェックせずNoneを「伝播」助けました。

あなたが見ているように、ここでは多くの型推論がありません。 あなたの混乱の根源は、通常mapfilter(他のものの中でも)は通常何らかのコレクションに関連付けられている可能性があるので、コレクションでリモートに似ているOption上で行うことは難しいかもしれません。そのために 私は、明示的であるためには、古典的なscala.Option cheat sheet

+0

3行目"scala> res0.map(name =>新しいjava.io.File(name))"のいずれかで、変数名はどこから来たのですか?私はそれがres0でなければならないと思いますよね? – chaotic3quilibrium

+0

@ chaotic3quilibrium REPLは自動的にあなたが入力した各式の値を割り当てるvalを作成し、res0、res1、res2などの名前を付けます。最初の行で 'Some(" c:\\ users \\ paolo ")'とタイプしたので、scalaは自動的にこれを 'val res0 = Some(" c:\\ users \\ paolo ")'と解釈し、 'res0'は' Some [java.lang.String] 'の型とSome(c:\ users \ paolo)という値を持っています。それから私は 'res0'に' map'を使い、 'option [java.io.File]'と 'Some(c:\ users \ paolo)'という値を持つ 'res1'を返しました。 –

+0

私はそれをもう一度読んで、今res0.mapを取得し、その名前はマップ関数のパラメータ名です。 – chaotic3quilibrium

2

後続ドットは、次の行のメソッドfilterに単純にチェーンされています。遊びに推論はありません。

これは

import java.io._ 

def getTemporaryDirectory(tmpArg : Option[String]) : File = { 
    tmpArg.map(name => new File(name)).filter(_.isDirectory).getOrElse(new File(System.getProperty("java.io.tmpdir"))) 
} 
+0

それは私が意味するものではありません。私はそれが一連​​のメソッド呼び出しであることを知っています。私が得られないのは、次のメソッドが呼び出されるときに返される型です。タイプ推論は、(私の未経験の目から)どのタイプが各関数によって返されているのかを隠しています。 – chaotic3quilibrium

+0

@chaotic - しかし、この例では必ずしも実際の型推論はありませんが、メソッド引数として使用される関数の型を除きます。 (...)。getOrElse(new File()) 'のみ' ... 'はちょっとした関数オブジェクトでなければならないでしょうインスタンス化。 –

+0

@Michal私はJavaでこれを行うことができます。しかし、一般的に私はそのようなJavaシーケンスで発生する可能性があるほとんどの活動を知っています。 Scalaにはいろいろなことがありますが、どれがシーケンスを読み理解しているのか分かりません。私のギャップは、filter()が最後のドットが使用していたOption [File]を返すことでした。 – chaotic3quilibrium

1

にあなたを参照してください。

def getTemporaryDirectory(tmpArg : Option[String]) : java.io.File = { 
    val v1: Option[java.io.File] = tmpArg.map(name => new java.io.File(name)) 
    val v2: Option[java.io.File] = v1.filter(_.isDirectory) 
    val v3: File = v2.getOrElse(new java.io.File(System.getProperty("java.io.tmpdir"))) 
} 

はここで起こっ型推論の多くは、まだあります、そしてダニエル・スピーバックはan excellent presentation on type inferenceを持っています。これは、Scalaがどのような型を推論できるのかを実際に知ることができます。

この例では、

Option[A]mapメソッドのシグニチャはmap[B](f: A => B): Option[B]です。 tmpArgOption[String]なので、コンパイラはパラメータの型がString => Bであることを認識します。今度はnameStringであると推測できます。関数を調べると、関数がFileを返すことがわかります。コンパイラは、パラメータの型がString => Fileであり、このmap呼び出しがOption[File]を返すと推測できます。

Option[A]の方法は、filter (p: A => Boolean): Option[A]という署名があります。関数リテラル_.isDirectoryは、単にx => x.isDirectoryの略語です。 Aが今度はFileであるとすれば、コンパイラは_Fileであると推測できます。結果はOption[File]です。

最後にのgetOrElseメソッドがあり、記号はgetOrElse[B >: A](default: => B): Bです。 B >: Aの構文では、タイプパラメータBAと同じまたはスーパータイプに制約されています。構文=> Bは、パラメータをby-name/lazyパラメータとして指定します。必要な場合にのみ評価されます。渡されたパラメータのタイプはFileであり、BFileであり、getOrElseFileです。

+0

それは私が特定の問題で探していたものです。だから、.mapと.filterはどちらもOption [File]を返します。このようなScalaコードのスニペットを「解き放つ」ために使用できるツール上のアイデアなので、型の推論を始めるための重要なポイントをすべて学ぶことができます。 – chaotic3quilibrium

+1

@ chaotic3quilibrium Eclipseの用語にカーソルを合わせると、そのタイプが表示されます。 –

+0

驚くばかり!私はそれもやってみよう。 Tyvm。 – chaotic3quilibrium

1

REPLと一緒に追加のリソースを使用すると、IDEを使用して連鎖式を分解または注釈を付けることができます。

例えばIntelliJでは、メソッド呼び出しの上にマウスを置いて型シグネチャを見ることができます。ソースがあれば、クリックして実装を見ることができます。

しかし、Danielのアドバイスを書いておけば、Programming in Scalaのような本は、型推論と言語の構文規則(この例では混乱の原因となる可能性があります)を扱うより簡単な出発点になります。

+0

私はEclipse IDEを使用しています。しかし、コードスニペットの上にマウスを置いたときに、それが明らかになったタイプに気付かなかった。それはとても役に立ちます。 – chaotic3quilibrium

関連する問題