ハードウェアの気になるあれこれ

技術的に興味のあることを調べて書いてくブログ。主にハードウェアがネタ。

Chiselの勉強 - Chisel Bootcamp - Module 1(2)

スポンサーリンク

前回の記事でChisel Bootcampのモジュール1を読み進めていった。半分くらいで分割したので、今日はその残りをまとめていく。

www.tech-diningyo.info

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
  • 一回のイタレーション実行後の増分は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.Randomscala.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のテキストに若干注意めいたことが書いてあるので、訳して載せておく。

Scalafor式は多くのトリックを持っているので、必要とされる多くの伝統的なイタレーション処理を直感的に扱うことが出来る。しかしそれは必ずしも便利な方法であるとは限らない。配列の各要素を足し合わせるような処理は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パッケージの下の全てのクラスとメソッドをインポートしている。

pythonfrom A import *みたいな宣言の扱いのようで、ここでは"_"がワイルドカードの意味を持っている。

2つ目の宣言ではchisel3.iotestersから特定のクラスのみをインポートしている。

なるほどパッケージの下の特定の何かを取り出す際には{}が必要ということのようだ。

2回にまとめようとしたら、思いの外分量があった。。。。

この後にクラスの話が出てくるのだが今日はここまで。