9

パターンに遭遇することが多いので、Scala ライブラリに便利なメソッドがないか調べてみました。

それを関数にしましょうf: A => Option[B]f最初のx, f(f(f(x).get).get...), まで繰り返し呼び出しを行い、最後の非値を保持したいと思いfます。NoneNone

私はこれの実装を書きました:

@tailrec
def recurrentCallUntilNone[B](f: B => Option[B], x: B): B = f(x) match {
  case Some(y) => recurrentCallUntilNone(f, y)
  case None => x
}

これはすでに標準ライブラリに実装されていますか?

この使用例は、現在の位置を保持するリスト (Zipper) の場合です。を呼び出すとnextNone現在の位置の後に要素がない場合、またはOption同じリストの が現在の位置がインクリメントされている場合に返されます。上記のメソッドを使用するendと、リストを最後までシークするメソッドを構築できます。

4

4 に答える 4

2

あなたがしていることは、非常に特殊なタイプのトランポリンのように見えます。より一般的なケースでは、 の代わりにケース クラスにラップされた関数を使用しOption、さまざまな引数と戻り値の型をサポートします。

Calin-Andrei が指摘するように、トランポリンはTailCalls オブジェクトを使用して標準ライブラリで利用できます。

最初のリンクから:

def even2(n: Int): Bounce[Boolean] = {
  if (n == 0) Done(true)
  else Call(() => odd2(n - 1))
}
def odd2(n: Int): Bounce[Boolean] = {
  if (n == 0) Done(false)
  else Call(() => even2(n - 1))
}
trampoline(even2(9999))

sealed trait Bounce[A]
case class Done[A](result: A) extends Bounce[A]
case class Call[A](thunk: () => Bounce[A]) extends Bounce[A]

def trampoline[A](bounce: Bounce[A]): A = bounce match {
  case Call(thunk) => trampoline(thunk())
  case Done(x) => x
}

標準ライブラリを使用するようになりました

import scala.util.control.TailCalls._

def even2(n: Int): TailRec[Boolean] = {
  if (n == 0) done(true)
  else tailcall(odd2(n - 1))
}
def odd2(n: Int): TailRec[Boolean] = {
  if (n == 0) done(false)
  else tailcall(even2(n - 1))
}
even2(9999).result
于 2013-07-29T14:51:58.387 に答える
2

どうですか:

Stream.iterate(Some(x)) { x => x.flatMap(f _) }.takeWhile { _.isDefined }.last

アップデート

または、よりきちんとした私見(単一のトラバーサルのみ):

val result = {
  val xs = Stream.iterate(Some(x)) { x => x.flatMap(f _) }
  (xs zip xs.tail) collectFirst {
    case (Some(x), None) => x
  } get
}

collectFirsta で開始できないため、呼び出しても安全であることに注意してくださいNone(そうしないと、無限ループが発生する可能性があります)。

于 2013-07-29T16:32:18.500 に答える
1

必要に応じて、オプションからストリームを作成し、ストリーム関数を使用して最後に定義された要素を取得できます。(または、未定義要素の前の最後の定義要素)

def options[B](f: B => Option[B], initialValue: Option[B]): Stream[Option[B]] = {
  initialValue #:: options(f, initialValue.map(f(_)).flatten)
}

options.takeWhile(_.isDefined).last
于 2013-04-19T02:49:12.220 に答える
1

美人コンテストの場合、カリー化を使用して、既存のものをあなたが話していたモンスターに変換する機能を構築できます。

def composeUntilTheEnd[B](f: Option[B] => Option[B])(x: Option[B]): Option[B] = 
        if (f(x) != None) composeUntilTheEnd(f)(f(x))
        else x

def ff = composeUntilTheEnd((x:Option[Int]) => x)_

これでff、意図した動作が得られます。

于 2013-04-07T20:45:31.297 に答える