私はRex Kerrのanswer上のビットを拡張してみましょう。 Scalaのコレクションには本当に3つの中心的なクラスがあり、それらのうち2つだけが実際にコレクションの一部です。それらはTraversable
,Iterable
およびIterator
です。
最も基本的なコレクションはTraversable
です。 Traversable
には、必要なものは1つだけです。メソッドforeach
を実装する必要があります。したがって、コレクションの各要素に適用される関数を渡すことができる限り、Traversable
にすることができます。たとえば:
class Three[A](a: A, b: A, c: A) extends Traversable[A] {
def foreach[U](f: (A) => U) {
f(a); f(b); f(c)
}
}
これは、このようなmap
やfilter
などの方法がThree
を返さないでしょうが、あなたにTraversable
すべてのメソッドを与えるが、Traversable
ます。あなたが定義したクラスを返すことははるかに難しく、多くの特殊なクラスではできません。たとえば、Three
は実行できません。Three
のfilter
がいくつか削除されているためですか?
次に、Iterator
があります。これは実際にはTraversable
とほぼ同じですが、異なる方法です。 Iterator
は、next
とhasNext
の2つのメソッドを定義する必要があります。たとえば:
class Three[A](a: A, b: A, c: A) extends Iterator[A] {
private var aReady, bIsRead, cIsRead = false
def hasNext = !(aIsRead && bIsRead && cIsRead)
def next = (aIsRead, bIsRead, cIsRead) match {
case (false, _, _) => aIsRead = true; a
case (_, false, _) => bIsRead = true; b
case (_, _, false) => cIsRead = true; c
case _ => Iterator.empty.next
}
}
これは主にTraversable
のメソッドと同じように見えるIterator
のすべてのメソッドを、提供します。これらの方法の違いは、ほとんどの場合、Iterator
は1度しか使用できないという事実に関連しています。
最後に、Iterable
があります。 Iterable
であるためには、あるクラスは1つのメソッド、iterator
を実装する必要があります。このメソッドは、そのクラスに対してIterator
を返します。例:
class Three[A](a: A, b: A, c: A) extends Iterable[A] {
// not necessary, but may offer a more efficient implementation
override def foreach[U](f: (A) => U) {
f(a); f(b); f(c)
}
def iterator = new Iterator[A] {
private var aReady, bIsRead, cIsRead = false
def hasNext = !(aIsRead && bIsRead && cIsRead)
def next = (aIsRead, bIsRead, cIsRead) match {
case (false, _, _) => aIsRead = true; a
case (_, false, _) => bIsRead = true; b
case (_, _, false) => cIsRead = true; c
case _ => Iterator.empty.next
}
}
}
質問に戻るには、期待される動作が何であり、どのようにしたいかを考慮する必要があります。特に、Scalaコレクションには「下」と「左」という概念はありません。つまり、Node
はScalaコレクションを返すメソッドを持つことができますが、はになります。Rex Kerrの解説を参照してください。
EDIT私はレックスカーのとは別の例を挙げましょう。ここではTraversable
Node
を実行し、トラバーサルの順番を選択できます。
class Node[A] extends Traversable[A] {
var left: Node[A] = _
var down: Node[A] = _
var traverseLeft = true
var value: A = _
def foreach[U](f: (A) => U) = if (traverseLeft) foreachLeft(f) else foreachDown(f)
def foreachLeft[U](f: (A) => U) { f(value); if (left != null) left.foreachLeft(f) }
def foreachDown[U](f: (A) => U) { f(value); if (down != null) down.foreachDown(f) }
}
だから、これNode
はTraversable
で、(それはまだなど、map
からNode
を返さないでしょうが - これについて他の質問を見て)それはTraversable
すべてのメソッドをサポートしています。フラグ(traverseLeft
)で左または下を走査するかどうかを選択でき、すべての通常のTraversable
メソッドは、メソッドが呼び出されたノードに設定されているものを使用します。
しかし、これは良いモデルではありません。私はむしろRex Kerrのイテレータを左下に返すか、Scalaコレクションを完全に残して、Kiamaで処理されたものと一緒に行くRex Kerrのソリューションに行きたいと思います。後者はまったく別のパラダイムですが、Scalaに変換されたコードに慣れ親しんでいるものではありません。
もちろん、私はこれを行うことができます。しかし、すべてのケースで繰り返されるたくさんのコードがあります - それが私が避けようとしているものです。問題は私が記述したより少し悪いかもしれません。多分6-10のクラスがあり、それぞれ少なくとも1つのリンクされたリストを持っていますので、mummumとして上の振る舞いを特性に一般化したいと思います。しかし、。私はまた、理解、foreachなど(これまでのところ、 'find'、' foreach'、 'forall'、' exists'、 'corresponding'に相当するものが見つかりました) –
左/ 、ただ 'trait DoubleIterable [A] {var left:A; var down:A;/* iterator defs here//} 'それから' class NodeはDoubleIterable [Node] 'を継承しますか? –
うん。私が望むものよりもさらに重複しています。 –