1

Bar と呼ぶ Foos のコレクションを持つクラスがあります。Foo には、次のように Bar レベルで集計したい数値を返すメソッドがいくつかあります。

  def attribute1(inputs: Map[Int, Double]) = 
foos.foldLeft(0d)((sum, foo) => sum + foo.attribute1(inputs(foo.id)))

これらのさまざまな属性を集約するために、次の形式の n 関数を使用できます。

  def attributeN(inputs: Map[Int, Double]) = 
foos.foldLeft(0d)((sum, foo) => sum + foo.attributeN(inputs(foo.id)))

しかし、それは醜いです-反復と合計が繰り返されるという事実は嫌いです。それを抽象化したいので、次のようなことができます:

def attribute1(inputs: Map[Int, Double]) = aggregate(Foo.attribute1, inputs)
private def aggregate(f: Double => Double) = foos.foldLeft(0d)((sum, foo) => sum + foo.f(inputs(foo.id)

もちろん、 Foo.attribute1 を関数として参照できないため、これは機能しません。関数インスタンスではありません。

私は基本的にさまざまな解決策に出くわしましたが、すべての結果は、少なくともヘルパーを使用しない場合と同じくらい冗長または複雑な各集計方法のコードになり、反復の重複が残っています。

ここで期待しすぎているだけかもしれませんが、これを行うためのエレガントな方法があることはほぼ確実です。Scala は私を逃れています。ですから、ここで答えてくれる Scala 達人なら誰でも - 事前に感謝します!

4

3 に答える 3

2

あなたがやろうとしていることはわかりませんが、scala では次のような数値を返すメソッドがあります。

def attribute1 = 5

関数です。まあ、一種の... タイプを持つ関数として見ることができます() => Int(引数を取らず、整数を返します)。omn​​ipresent を使用_して scala にattribute1関数に変換するように指示するだけです。これが出発点として役立つかどうかを確認してください。

scala> class Foo {
     | def attribute1=5
     | def attribute2=2
     | }
defined class Foo

scala> val foo=new Foo
foo: Foo = Foo@4cbba0bd

// test takes a function of type () => Int and just applies it (note 
// the f() followed by () in the right-hand side to say we want to apply f
scala> def test(f: () => Int) = f()
test: (f: () => Int)Int

// the _ after foo.attribute1 tells scala that we want to use 
// res2.attribute as a function, not take its value 
scala> test(foo.attribute1 _)
res0: Int = 5
于 2013-09-19T16:12:29.787 に答える
0

@Nikitaの答えに基づいて、退屈なメソッドからもう少し冗長性を取り除きたい場合は、aggregateメソッドをカリー化できます:

def aggregate(f: (Foo, Double) => Double)(inputs: Map[Int, Double]): Double =
  foos.foldLeft(0d)((sum, foo) => sum + f(foo, inputs(foo.id)))

def aggregateAttribute1: Map[Int, Double] => Double =
  aggregate(_.attribute1(_))
于 2013-09-20T16:11:00.873 に答える