理解のために、私は単に印刷ステートメントを置くことはできません:
def prod (m: Int) = {
for (a <- 2 to m/(2*3);
print (a + " ");
b <- (a+1) to m/a;
c = (a*b)
if (c < m)) yield c
}
しかし、ダミーの割り当てで簡単に回避できます。
def prod (m: Int) = {
for (a <- 2 to m/(2*3);
dummy = print (a + " ");
b <- (a+1) to m/a;
c = (a*b)
if (c < m)) yield c
}
副作用であり、(これまでのところ)開発中のコードでのみ使用されているので、より良いアドホックソリューションはありますか?
副作用以外に、なぜ使わないのかという深刻な問題はありますか?
Rex Kerrとの話し合いから、元のコードを表示する必要性が高まっています。これは少し複雑ですが、質問(2x .filter、最後にメソッドを呼び出す)には関連していないようですが、レックスのパターンを適用しようとして失敗したので、ここに投稿します。
def prod (p: Array[Boolean], max: Int) = {
for (a <- (2 to max/(2*3)).
filter (p);
dummy = print (a + " ");
b <- (((a+1) to max/a).
filter (p));
if (a*b <= max))
yield (em (a, b, max)) }
これが私の試みです-(b * a).filterは間違っています。結果はintであり、フィルター可能なintのコレクションではないからです。
// wrong:
def prod (p: Array[Boolean], max: Int) = {
(2 to max/(2*3)).filter (p).flatMap { a =>
print (a + " ")
((a+1) to max/a).filter (p). map { b =>
(b * a).filter (_ <= max).map (em (a, b, max))
}
}
}
パートIIはコメントに属していますが、そこに書かれていると読むことができません。最後に削除するかもしれません。失礼します。
わかりました-これがコードレイアウトにおけるレックスの最後の答えです:
def prod (p: Array[Boolean], max: Int) = {
(2 to max/(2*3)).filter (p).flatMap { a =>
print (a + " ")
((a+1) to max/a).filter (b => p (b)
&& b * a < max).map { b => (m (a, b, max))
}
}
}
これはあなたがそれを書く必要がある方法です:
scala> def prod(m: Int) = {
| for {
| a <- 2 to m / (2 * 3)
| _ = print(a + " ")
| b <- (a + 1) to (m / a)
| c = a * b
| if c < m
| } yield c
| }
prod: (m: Int)scala.collection.immutable.IndexedSeq[Int]
scala> prod(20)
2 3 res159: scala.collection.immutable.IndexedSeq[Int] = Vector(6, 8, 10, 12, 14
, 16, 18, 12, 15, 18)
開始Scala 2.13
、連鎖操作 tap
は標準ライブラリに含まれており、パイプラインの中間状態を出力する必要がある場合は、最小限の煩わしさで使用できます。
import util.chaining._
def prod(m: Int) =
for {
a <- 2 to m / (2 * 3)
b <- (a + 1) to (m / a.tap(println)) // <- a.tap(println)
c = a * b
if c < m
} yield c
prod(20)
// 2
// 3
// res0: IndexedSeq[Int] = Vector(6, 8, 10, 12, 14, 16, 18, 12, 15, 18)
tap
チェーン操作は、値(この場合はprintln
)に副作用(この場合はa
)を適用し、値( a
)手つかず:
def tap [U](f:(A)=> U):A
コードを変更せずに一連のtap
sを使用できるため、デバッグ時に非常に便利です。
def prod(m: Int) =
for {
a <- (2 to m.tap(println) / (2 * 3)).tap(println)
b <- (a + 1) to (m / a.tap(println))
c = (a * b).tap(println)
if c < m
} yield c
ループや中間結果などがすべて互いに混ざり合うため、一般的に、コーディングのスタイルを理解するのはかなり難しいと思います。 forループの代わりに、次のように記述します。
def prod(m: Int) = {
(2 to m/(2*3)).flatMap { a =>
print(a + " ")
((a+1) to m/a).map(_ * a).filter(_ < m)
}
}
これにより、printステートメントなどの追加も簡単になります。
副作用のあるステートメントを理解のために(または実際には関数の途中に)置くのは良いスタイルではないようですが、デバッグを除いて、それを何と呼ぶかは実際には重要ではありません(「デバッグ」 「いい名前のようです)。
本当に必要な場合は、中間の値を割り当てることで、懸念事項をある程度分離したほうがよいと思います。 (あなたのオリジナルはよりうまくレイアウトされています):
def prod (p: Array[Boolean], max: Int) = {
for {
a <- (2 to max / (2 * 3)) filter p
debug = print (a + " ")
b <- ((a + 1) to max / a) filter p
if a * b <= max
} yield em(a, b, max)
}
になります
def prod2 (p: Array[Boolean], max: Int) = {
val as = (2 to max / (2 * 3)) filter p
for(a <- as) print(a + " ")
as flatMap {a =>
for {
b <- ((a + 1) to max / a) filter p
if a * b <= max
} yield em(a, b, max)
}
}