1

引数をとらないadefを使用して実装できます。valdef

trait T { def foo: Int }
class C(val foo: Int) extends T

なぜこれを拡張して、defN個の引数をvalであるvalに実装することができないのFunctionNですか?私は次のようなものを実装できるようにしたいと思っています。

def expensiveOperation(p: Int => Boolean) : List[Int]

怠惰な機能付きval。何かのようなもの:

val expensiveOperation = {
    val l = //get expensive list
    l.filter _ //partially applied function
}

この構文は2.8では機能しないようです。足りないものがありますが、パラメータを関数として実装できないのはなぜですか?defval

4

4 に答える 4

2

さて、編集後、私はあなたが何を求めているのか理解していると思います。しかし、型シグネチャが一致しないため、やりたいことができません。

def x: Int = 5
val x: Int = 5

どちらの場合も、何も提供せずにInt(この場合は5)を取り戻します。素晴らしい!

def expensive(p: Int => Boolean): List[Int]

今、あなたは何かを供給します。しかし、valはどこかに保存されたオブジェクトにすぎません。ラベルが参照するオブジェクトに何かを提供することはできますが、それはラベル'x'に何かを提供することと同じではありません。

valでオーバーライドする場合は、次のdefを使用する必要があります。

def expensive: (Int=>Boolean)=>List[Int]

これで、パラメーターなしで呼び出すものがあり、Int => Boolean関数を取り、その代わりにList[Int]を返すことができるものが返されます。これはまさにvalで得られるものです。どちらの場合も、必要な機能を備えたオブジェクトを返すものの名前があります。

(Scalaでは、valsは実際には、パラメーターを受け取らず、非表示フィールドにあるものを返すgetterメソッドを使用して非表示フィールドとして実装されます。したがって、実際にはdefと同じメソッドです。)

于 2010-01-28T16:57:26.263 に答える
2

Avalは計算されてフィールドに格納されるため、引数を取りません。しかし、私が過去2日間にメーリングリストで行った広範な投稿を参照するだけかもしれません。

または、むしろ、Javaの観点から考えてみましょう。ScalaはjvmレベルでJavaと互換性があり、jvmのルールに必ず従う必要があるためです。最初のクラスから始めましょう:

abstract class X {
  def expensiveOperation(p: Int => Boolean) : List[Int] 
}

それでは、拡張してみましょう。

abstract class Y extends X {
  override val expensiveOperation: ((Int) => Boolean) => List[Int]
}

したがって、Javaから、クラスには、を受け取って返すXメソッドがあることがわかります。expensiveOperationFunction1[Int, Boolean]List[Int]

次に、クラスに移動しYます。当然、同じメソッドを定義する必要がありますが、expensiveOperation引数を受け取らずにを返すgetterも定義する必要がありますFunction1[Function1[Int, Boolean],List[Int]]

この追加のメソッドが存在しない限り、それは実行可能かもしれませXん。それでは、それを定義しましょう:

class Z extends Y {
  override val extensiveOperation = new Function1[Function1[Int, Boolean], List[Int]] {
    def apply(p: Int => Boolean) = List range (1, 10) filter p
  }
}

それはどのように定義されますか?Scalaはの本体を(ゲッターではなくパラメーターを受け取るもの)applyの本体としてコピーしますか?expensiveOperationそれはまだ実行可能かもしれません。ただし、別のことを試してみましょう。

class W(f: ((Int) => Boolean) => List[Int]) extends Y {
  override val extensiveOperation = f
}

では、パラメータの受信をどのようにオーバーライドしますextensiveOperationか?私たちはそれを次のように書くことができると思います:

override def extensiveOperation(p: Int => Boolean) = extensiveOperation.apply(p)

それは実行可能です。しかし、私は個人的に、それは少し複雑だと思います。私の提案:短いSIDを書いて、Scalaメーリングリストで合意を得てください。ただし、それを実装するコードがなければ、採用される可能性はあまりないと思いvalます。Scalaは、オーバーライドされているかどうかを判断するために、すべての関数型を追跡する必要がありますdef

于 2010-01-28T19:48:10.893 に答える
1

あなたはいつでもそれをあなたのvalに転送することができます:

trait T {
  def expensiveOperation(p: Int => Boolean) : List[Int]
}

class C extends T {
  def expensiveOperation(p: Int => Boolean): List[Int] = {
      expensiveOperationVal(p) 
  }
  val expensiveOperationVal = { p: (Int=>Boolean) =>
    // ... lazy stuff
    List(1,2,3)
  }
}

そして、これはあなたの質問に答えませんが、あなたの// ... get expensive listコードが述語に依存していない限り、あなたは次のようなpことをすることができます:

class C extends T {
  def expensiveOperation(p: Int => Boolean): List[Int] = {
      myExpensiveList filter p 
  }
  lazy val myExpensiveList = {
    val l = // ... expensive stuff
    l
  }
}
于 2010-01-28T16:46:40.973 に答える
0

編集:わかりました、私はあなたが実際に何を意味するのか理解していませんでした。しかし、あなたが私が思ったことを意味していたなら...

省略された構文を使用して、操作を適用するvalを作成できます。

val expensive = (p: (Int) => Boolean) => {
  val l = List(1,2,3,4)
  l filter p
}
scala> expensive(_<3)
res1: List[Int] = List(1,2)

しかし、これは実際にはリストをキャッシュしません。これは私が望むものです。その理由は、この省略形の構文では、=>以降のすべてがFunction1のapplyメソッドに入れられるためです。おそらく、リストを次のように保存する必要があります。

val expensive = new Function1[Int=>Boolean,List[Int]] {
  lazy val l = List(1,2,3,4)
  def apply(p: (Int) => Boolean) = { l filter p }
}

そのため、私が知っている素晴らしい速記はありません。

編集:そのブロックの外にリストを作成することに満足している場合は、省略形があります(コメントも参照してください):

val expensive = List(1,2,3,4).filter _

scala> expensive(_ < 3)
res6: List[Int] = List(1, 2)
于 2010-01-28T15:11:20.117 に答える