2011-06-24 13 views
12

一般的な質問は、計算の実際の結果の他に、メソッドから追加の情報を返す方法です。しかし、私はこの情報を黙って無視することができます。メソッドからオプションの情報を返す方法は?

例えばdropWhileIteratorとすると、返される結果は、反復されたイテレータです。しかし、たぶん時々、落とした要素の数に興味があるかもしれません。

dropWhileの場合、この情報は、イテレータにインデックスを追加し、その後にドロップされたステップの数を計算することによって外部的に生成することができます。しかし、一般的にこれは不可能です。

単純な解決法は、実際の結果とオプションの情報を含むタプルを返すことです。しかし、私はメソッドを呼び出すたびにタプルを処理する必要があります。たとえオプションの情報に興味がなくても。

このようなオプションの情報を収集するための巧妙な方法があるのか​​どうかという疑問はありますか?

多分Option[X => Unit]のコールバック関数のパラメータはNoneになるでしょうか?もっと巧妙なものがありますか?

答えて

15

...

あなたはこの宣言できます。Aへの暗黙的な変換と

case class RichResult[+A, +B](val result: A, val info: B) 

を:次に

implicit def unwrapRichResult[A, B](richResult: RichResult[A, B]): A = richResult.result 

def someMethod: RichResult[Int, String] = /* ... */ 

val richRes = someMethod 
val res: Int = someMethod 
次に、あなたのオリジナルの方法を考える(とケースを使用)

package info { 
    trait Info[T] { var data: Option[T] } 
    object Info { 
    implicit def makeInfo[T]: Info[T] = new Info[T] { 
     var data: Option[T] = None 
    } 
    } 
} 

次のように実装されています:ここで

+0

これについて考えてみましょう。欠点は、 'A'を推論できないときにタイプアノテーションが必要であるということです。 – ziggystar

+0

'val'に代入して暗黙の変換の恩恵を受けるには、型の注釈が必要です。 –

+0

ところで、あなたは型の値を使うこともできます: 'val res = someMethod:Int'。 –

5

これは間違いなく賢明なことではありませんが、追加情報を削除するメソッドを作成するだけで済みます。ここではちょうど私の2セント

def removeCharWithCount(str: String, x: Char): (String, Int) = 
    (str.replace(x.toString, ""), str.count(x ==)) 

// alias that drops the additional return information 
def removeChar(str: String, x: Char): String = 
    removeCharWithCount(str, x)._1 
3

は(より現実的な例で、いくつかの編集で)私のテイクで提供するために

object Test extends App { 
    def dropCounterIterator[A](iter: Iterator[A]) = new Iterator[A] { 
    def hasNext = iter.hasNext 
    def next() = iter.next() 
    override def dropWhile(p: (A) => Boolean): Iterator[A] = { 
     var count = 0 
     var current: Option[A] = None 
     while (hasNext && p({current = Some(next()); current.get})) { count += 1 } 
     current match { 
     case Some(a) => Iterator.single(a) ++ this 
     case None => Iterator.empty 
     } 
    } 
    } 

    val i = dropCounterIterator(Iterator.from(1)) 
    val ii = i.dropWhile(_ < 10) 
    println(ii.next()) 
} 

と情報にアクセスすると、コードは少しだけ変更されます:

import info.Info // line added 

object Test extends App { 
    def dropCounterIterator[A](iter: Iterator[A]) = new Iterator[A] { 
    def hasNext = iter.hasNext 
    def next() = iter.next() 
    // note overloaded variant because of extra parameter list, not overriden 
    def dropWhile(p: (A) => Boolean)(implicit info: Info[Int]): Iterator[A] = { 
     var count = 0 
     var current: Option[A] = None 
     while (hasNext && p({current = Some(next()); current.get})) { count += 1 } 
     info.data = Some(count) // line added here 
     current match { 
     case Some(a) => Iterator.single(a) ++ this 
     case None => Iterator.empty 
     } 
    } 
    } 

    val i = dropCounterIterator(Iterator.from(1)) 
    val info = implicitly[Info[Int]] // line added here 
    val ii = i.dropWhile((x: Int) => x < 10)(info) // line modified 
    println(ii.next()) 
    println(info.data.get) // line added here 
} 

何らかの理由で型の推論が影響を受けることに注意してください私はdropWhileに渡された関数の型に注釈を付ける必要がありました。

0

Stateモナドが計算を介してカウンタをスレッディングする場合、dropWhileMが必要です。

関連する問題