[解決済み] Scala の currying と部分的に適用される関数
質問
このサイトには、以下のような質問があるようです。 何 curryingと部分適用関数がありますが、どう違うのかについて質問しています。簡単な例として、偶数を求めるための curried 関数を紹介します。
def filter(xs: List[Int], p: Int => Boolean): List[Int] =
if (xs.isEmpty) xs
else if (p(xs.head)) xs.head :: filter(xs.tail, p)
else filter(xs.tail, p)
def modN(n: Int)(x: Int) = ((x % n) == 0)
これを使うには次のように書けばいいわけです。
val nums = List(1,2,3,4,5,6,7,8)
println(filter(nums, modN(2))
を返します。
List(2,4,6,8)
. しかし、この方法で同じことができることがわかりました。
def modN(n: Int, x: Int) = ((x % n) == 0)
val p = modN(2, _: Int)
println(filter(nums, p))
も返す。
List(2,4,6,8)
.
そこで質問ですが、この2つの主な違いは何でしょうか?これは、片方を使用する理由を示すには単純すぎる例でしょうか。
どのように解決するのですか?
意味的な違いについては にリンクされている答えです。 .
機能的には、それほど大きな差はないように思えますが。それを確かめるために、いくつかの例を見てみましょう。まず、通常の機能です。
scala> def modN(n: Int, x: Int): Boolean = ((x % n) == 0)
scala> modN(5, _ : Int)
res0: Int => Boolean = <function1>
ということで、部分的に適用された
<function1>
を取り、それを
Int
というのは、すでに最初の整数が与えられているからです。ここまではいい感じです。さて、次はキュアリングです。
scala> def modNCurried(n: Int)(x: Int): Boolean = ((x % n) == 0)
この記法だと、素朴に次のようになりますね。
scala> modNCurried(5)
<console>:9: error: missing arguments for method modN;
follow this method with `_' if you want to treat it as a partially applied function
modNCurried(5)
そこで 複数パラメータリスト 記法は、(不必要なオーバーヘッドを避けるためと思われますが)実際にはすぐに curried 関数を作成するのではなく、curried にしたいことを明示的に指定するのを待ちます(この記法にはいくつかの その他の利点 もあります)。
scala> modNCurried(5) _
res24: Int => Boolean = <function1>
これは前に得たものと全く同じものであり、表記を除けば違いはない。もう一つの例です。
scala> modN _
res35: (Int, Int) => Boolean = <function2>
scala> modNCurried _
res36: Int => (Int => Boolean) = <function1>
これは、quot;normal" 関数を部分的に適用すると、すべてのパラメータを受け取る関数になり、一方、複数のパラメータリストを持つ関数を部分的に適用すると、関数のチェーンが作成されることを示しています。 パラメータリストごとに1つ という関数の連鎖を作り出し、そのすべてが新しい関数を返します。
scala> def foo(a:Int, b:Int)(x:Int)(y:Int): Int = a * b + x - y
scala> foo _
res42: (Int, Int) => Int => (Int => Int) = <function2>
scala> res42(5)
<console>:10: error: not enough arguments for method apply: (v1: Int, v2: Int)Int => (Int => Int) in trait Function2.
Unspecified value parameter v2.
ご覧のように、最初のパラメータリストである
foo
の最初のパラメータリストには2つのパラメータがあるので、 カリードチェインの最初の関数には2つのパラメータがあります。
要約すると、部分的に適用された関数は、機能性の点で、カールされた関数とあまり変わりません。これは、任意の関数を曲線化された関数に変換できることを考えると、簡単に検証できます。
scala> (modN _).curried
res45: Int => (Int => Boolean) = <function1
scala> modNCurried _
res46: Int => (Int => Boolean) = <function1>
ポストスクリプト
注意
あなたの例の
println(filter(nums, modN(2))
の後にアンダースコアがなくても動作するのは
modN(2)
は,Scalaコンパイラがプログラマの便宜のためにアンダースコアを仮定しているだけのようです.
追加です。 asflierl が正しく指摘しているように、Scala は "normal" 関数を部分的に適用する際に型を推論することができないようです。
scala> modN(5, _)
<console>:9: error: missing parameter type for expanded function ((x$1) => modN(5, x$1))
一方、複数パラメータリスト記法を用いて書かれた関数では、その情報は利用可能です。
scala> modNCurried(5) _
res3: Int => Boolean = <function1>
この回答 は、これが非常に有用であることを示しています。
関連
-
[解決済み] キュアリング」とは何ですか?
-
[解決済み] キュアリングと部分適用の違いは何ですか?
-
[解決済み] Scalaにおけるparam: _*の意味とは?
-
[解決済み] Scalaの慣用表現「flatmap that s*** 」はどこから来たのか?
-
[解決済み] Scalaのtraitでvalとdefの使い分けは?
-
[解決済み] に似た三項演算子。
-
[解決済み] flatMap/Map変換のfor-comprehensionで迷う。
-
[解決済み] scalaのマップを反復処理するには?
-
[解決済み] Scalaの複数パラメータリストと複数パラメータ/リストの違いは何ですか?
-
[解決済み] ScalaでCurryする2つの方法、それぞれのユースケースは?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 述語で配列を2つに分割するには?
-
[解決済み] Any、AnyVal、AnyRef、Objectの関係と、Javaコードでのマッピングについて教えてください。
-
[解決済み] Scalaにおけるval-mutableとvar-immutableの比較
-
[解決済み] なぜ `private val` と `private final val` は違うのですか?
-
[解決済み] Scalaで、リストから重複を取り除くにはどうしたらいいですか?
-
[解決済み] IntelliJ IDEAでSBTを使用してUber JAR (Fat JAR)をビルドする方法は?
-
[解決済み] ScalaにおけるNull/Nothing/Unitの使用法
-
[解決済み] Scalaの::と::の違いは何ですか?
-
[解決済み] Intellijのコンパイルに失敗する。"すでに次のように定義されています"
-
[解決済み] なぜScalaは複数のパラメータリストとリストごとの複数のパラメータの両方を提供するのですか?重複