前回の記事でChisel Bootcampのモジュール1を読み進めていった。半分くらいで分割したので、今日はその残りをまとめていく。
Module 1: Scala入門の続き
ということで今回はListから。
List
説明としては以下が記載されている。
Scalaは様々な集合的な(aggregate)、または順序的な(sequence)なオブジェクトを備えている。リストは配列と多くを同じとするものだが、追加や抽出において多くの追加の作業がサポートされている。
とりあえず例を見てみる。
val x = 7 val y = 14 val list1 = List(1, 2, 3) val list2 = x :: y :: y :: Nil // 別の宣言の仕方 val list3 = list1 ++ list2 // リストの追加(というか結合) val m = list2.length val s = list2.size val headOfList = list1.head // 先頭要素を取得 val restOfList = list1.tail // 末尾要素を取得 val third = list1(2)
- 実行結果
x: Int = 7 y: Int = 14 list1: List[Int] = List(1, 2, 3) list2: List[Int] = List(7, 14, 14) list3: List[Int] = List(1, 2, 3, 7, 14, 14) m: Int = 3 s: Int = 3 headOfList: Int = 1 restOfList: List[Int] = List(2, 3) third: Int = 3
実行結果を見ればだいたいやっていることは把握できると思うが、一応ポイントだけまとめていくと以下になる。
- 基本的な宣言は
val foo = List(0, 1, 2, ...)
となる - その他に
val foo = x :: y :: ... :: Nil
でも作れる。match
式とかで見かけた表現 - リストは
++
で結合できる - リストのサイズを取得するためには
List.size
/List.length
を参照する - 先頭の要素を取得する場合は
List.head
、末尾の要素を取得する場合はList.tail
を参照する - N番目の要素を取得するには
List[N-1]
を参照する
for式
ここは前にもやってるので、サンプルコードとまとめだけ。
to
を使用
for (i <- 0 to 7) { print(i + " ") } println()
- 実行結果
0 1 2 3 4 5 6 7
until
を使用
for (i <- 0 until 7) { print(i + " ") } println()
- 実行結果
0 1 2 3 4 5 6
by
によってステップ数を変更
for(i <- 0 to 10 by 2) { print(i + " ") } println()
- 実行結果
0 2 4 6 8 10
ここまでのfor
まとめ
ざっとまとめると以下の通り。
- 基本形は
for (i <- 範囲指定) { ブロック式 }
- 範囲指定は以下のように
to
/until
を使用する- N未満 :
i <- 0 to N
- N以下:
i <- 0 until N
- N未満 :
- 一回のイタレーション実行後の増分は
by N
で調節可能
List
のようなコレクション型のfor
式
Pythonのようにリストをfor
式に指定することで、全要素を処理するような使い方も可能
import scala._ val randomList = List(util.Random.nextInt(), util.Random.nextInt(), util.Random.nextInt(), util.Random.nextInt()) var listSum = 0 for (value <- randomList) { listSum += value } println("sum is " + listSum)
なお使用しているjupyter scala(almond)の影響により、Bootcampのコードをそのまま動かすと以下のようなエラーがてたため、上記のコードは先頭にimport scala._
を追加してutil.Random
がscala.util.Random
になるようにコードを修正している。(almondが使っているammoniteにRandomモジュールが存在しているためライブラリの読み出しが意図しないものになったため)
cmd11.sc:1: object Random is not a member of package ammonite.util val randomList = List(util.Random.nextInt(), util.Random.nextInt(), util.Random.nextInt(), util.Random.nextInt()) ^cmd11.sc:1: object Random is not a member of package ammonite.util
- 実行結果
sum is -1025315927 import scala._ randomList: List[Int] = List(239634353, -855410113, 573200358, -982740525) listSum: Int = -1025315927
Bootcampのテキストに若干注意めいたことが書いてあるので、訳して載せておく。
Scalaの
for
式は多くのトリックを持っているので、必要とされる多くの伝統的なイタレーション処理を直感的に扱うことが出来る。しかしそれは必ずしも便利な方法であるとは限らない。配列の各要素を足し合わせるような処理はcomprehensionsと呼ばれる多くの異なるコレクション型の要素を横断的に処理できる関数を使うことでもっと容易に処理が出来る。この後のモジュールでそのようなfor
式の用法についても見ていく。
Scalaを読む
ここは今後Chiselを使って設計を行っていくにあたって、どうScalaに取り組んでいくべきかの心構え的なことが書いてある。特に実行すべきコードもないので、それとなく訳した内容をペタリ。
Scalaのコードを読めるようになることや、一般的な命名規則、デザインパターン、ベストプラクティスを理解することはより効率的な開発を行えるChisel設計者になる際に非常に重要なステップです。コードを再利用できる可能性があるというのはChiselの優位性の一つですが、もしあなたが他の人の書いたコードを読むことが出来ないのなら、再利用は難しいものとなります。効率的に他の人のコードを解析出来ることはStackOverflowのようなお助けサイトからヒントを探すことを容易にします。
パッケージとインポート
これは以前のScalaの勉強ではやっていない。、、が、まあなんとなくわかるよね、うん。というか手前のfor
のとこでも使ってるし、うん。
まあ、とりあえず見ていく。
パッケージの宣言
package mytools class Tool1 { ... }
これが、パッケージの宣言。上記だと、mytools
の下にTool1
が存在することになる。
パッケージのインポート
使う際にはimport
で使用するものを宣言する
import mytools.Tool1
上記のようにするとTools
を使ったインスタンスを作成することが出来るようになる。
注意点としては以下のことが述べられている。
注意:パッケージ名はディレクトリの階層と同じ名前にするべきだ。これは必須ではないが、順守しない場合、一般的ではなく、診断の難しい問題を発生させることがある。パッケージ名は小文字で"_"のような文字で分割しないようにするのが一般的だ。これは時にわかりやすい名称をパッケージに付与することを難しくする。その場合のアプローチとしては構造を階層化することがある。例えば,
package good.tools
のように。わかりやすくなるように最善を尽くしてほしい。Chiselはそれ自体がこれらのルールに従わないようにすることを使って行う一種のゲームのようなものだ。
Chiselを使用する際に共通してインポートする宣言は以下のようなものになるようだ。
import chisel3._ import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}
最初の宣言では、chisel3パッケージの下の全てのクラスとメソッドをインポートしている。
pythonのfrom A import *
みたいな宣言の扱いのようで、ここでは"_"がワイルドカードの意味を持っている。
2つ目の宣言では
chisel3.iotesters
から特定のクラスのみをインポートしている。
なるほどパッケージの下の特定の何かを取り出す際には{}
が必要ということのようだ。
2回にまとめようとしたら、思いの外分量があった。。。。
この後にクラスの話が出てくるのだが今日はここまで。