15

whileループをシミュレートする関数を書くにはどうすればよいですか? 実行する条件と式の 2 つの引数を取る必要があります。

私は次のことを試しました:

val whileLoop: (Boolean,Any)=>Unit = (condition:Boolean, expression:Any) => {
 expression
 if(condition) whileLoop(condition,expression)
 () }    

しかし、うまくいかないようです。たとえば、私は配列を持っています:

val arr = Array[Int](-2,5,-5,9,-3,10,3,4,1,2,0,-20)    

また、変数iがあります:

var i = 0

arr のすべての要素を出力したい。次のコードでそれを行うことができます:

while(i<arr.length) { println(tab(i)); i+=1 }

whileLoop関数を使用して同じことをしたいと思います。しかし、変数を参照してそれを変更する関数を書くことはできません。たとえば、要素が1つだけの配列を使用してそれを渡すことができました

val nr = Array(0)

機能:

val printArray: Array[Int]=>Unit = (n:Array[Int]) => {
 println(arr(n(0)))
 n(0)+=1
 ()
}

そして、私のwhileLoopで使用します:

whileLoop(nr(0)<arr.length, printArray)

上記のコードを使用した後、StackOverflowErrorが発生し、nr(0) はゼロに等しくなります。また、次の機能:

val printArray: Array[Int]=>Unit = (n:Array[Int]) => {
 println(arr(nr(0)))
 nr(0)+=1
 ()
}

同じ結果が得られます。

正しい関数whileLoopを作成し、それを使用してすべてのarr要素を出力するにはどうすればよいですか?

アドバイスをよろしくお願いします。

4

2 に答える 2

29

実装の主な問題は、最初に を呼び出すときに、条件と式が 1 回だけ評価されることですwhileLoop。再帰呼び出しでは、式ではなく値を渡すだけです。

これは、名前による引数を使用して解決できます。

def whileLoop(cond : =>Boolean, block : =>Unit) : Unit =
  if(cond) {
    block
    whileLoop(cond, block)
  }

例として:

scala> val a = Array(1, 2, 3)
scala> var i = 0
scala> whileLoop(i < a.length, { println(i); i += 1 })
1
2
3

変数aiが正しく参照されていることに注意してください。内部的に、Scala コンパイラーは条件と式 (ブロック) の両方に対して関数を作成し、これらの関数は環境への参照を維持します。

whileLoopまた、シンタックス シュガーの素晴らしさをさらに高めるために、カリー化された関数として定義できることにも注意してください。

def whileLoop(cond : =>Boolean)(block : =>Unit) : Unit =
  if(cond) {
    block
    whileLoop(cond)(block)
  }

これにより、実際の while ループと同じように呼び出すことができます。

whileLoop(i < a.length) {
  println(a(i))
  i += 1
}
于 2012-11-11T13:45:14.303 に答える
2

これが私が思いついたものです。まず、関数には次の4つの引数が必要です。

- array which is yet to be processed
- predicate that tells the function when to stop
- function that takes the array to be processed and current state and produces a new state
- and state that is being propagated through the recurion:

私はコードがかなり自明だと思います:

def whileFunc[A,B](over: Array[A], predicate: Array[A] => Boolean, apply: (Array[A],B) => B, state: B):B = {
   val doIterate = predicate(over)
   if(doIterate) whileFunc(over.tail, predicate, apply, apply(over,state)) else state
}

これはもっと良くすることができますが、私はそれをできるだけシンプルに保つようにしました。配列内のすべての要素をカウントするには、次のように呼び出します。

scala>     whileFunc(Array(1,2,3), (a:Array[Int]) => !a.isEmpty,(a:Array[Int],s: Int) => s + a.head, 0)
res5: Int = 6

各要素を印刷するには:

whileFunc[Int, Unit](Array(1,2,3), (a:Array[Int]) => !a.isEmpty,(a:Array[Int],s: Unit) => print(a.head), Unit)
123

ちなみに、このようなことに興味があるなら、Scalaで関数型プログラミングを購入することをお勧めします。このような関数を実装するための2つの章があります。とても楽しいです。

于 2012-11-11T14:02:50.813 に答える