by shigemk2

当面は技術的なことしか書かない

プリプロセッサ、コンパイラ、アセンブラ、リンカ、インタプリタ

f:id:shigemk2:20140308195927j:plain

名称 内容 入力 出力
プリプロセッサ #defineや#includeなどを変換 c c
コンパイラ アセンブリ言語へ変換 c s
アセンブラ オブジェクトファイル(機械語が入っているファイル)を生成 s o
リンカ 実行可能ファイルを生成 o exeなど
インタプリタ 直接実行できないファイルを解釈して実行, sh/py/php/他のCPU用の実行可能ファイルなど なし

追記

内容が非常にアレであったため、大幅に書き換えた。

F#のシャドウイング

let hoge = 'hoge'

同じ名前の別の変数を定義すること。OCaml由来。

両方の値に同じ名前を付けると、先に付けたほうの名前が「見えなくなる」というだけです。これを「シャドウイング(shadowing)」と言いますが、F#において、値が変わっているように見えるのは実は値を上書きしているわけではなく、別の値に同じ名前を付けているだけなのです。

F#マスターへの道 - letとshadowing

ScalaのTraitをファイルで書く

概要

脱REPL的なものを目指す。

Scalaメモ(コンパイル、main) - garbage truck

コード

コードはこんな感じ。

trait.scala

trait Programmer {
  def coding = println("コーディングします")
}

// クラスが明示的に継承を行わない場合、extendsを使用してトレイトをミックスイン
class Person(val name: String) extends Programmer

trait Designer {
  def design = println("デザインします")
}

object Trait {
  def main(args: Array[String]) {
    // ほかのクラス/オブジェクトを継承する場合、withキーワードでトレイトをミックスインする
    var p1 = new Person("taro")
    p1.coding
    var p2 = new Person("taro") with Designer
    p2.coding
    p2.design
  }
}

コマンド

$ scala -version
Scala code runner version 2.10.3 -- Copyright 2002-2013, LAMP/EPFL
$ scalac trait.scala
(コンパイルしてクラスファイルTraitが生成される)
$ scala Trait
コーディングします
コーディングします
デザインします

参考文献

Scalaにおける複数トレイト使用時のコンストラクタの順序

概要

複数のトレイトを使用した場合、コンストラクタが実行される順番は、 スーパークラスのコンストラクタのあとに自分自身のコンストラクタが呼ばれて その後ミックスインしている。

コード

parant.scala

class Parent {
  println("Parent")
}

class Child extends Parent {
  println("Child")
}

trait A { println("trait A") }
trait B { println("trait B") }
trait C { println("trait C") }

object Parent {
  def main(args: Array[String]) {
    val c = new Child with A with B with C
    // println(c)
  }
}

コマンド

$ scalac parent.scala
$ scala Parent
Parent
Child
trait A
trait B
trait C

Scalaで別のトレイトで両方とも同じ名前のメソッドを実装していたら

概要

複数実装したトレイトの名前(シグネチャ)が同じ場合、
これらをまとめてミックスインしたらエラーになるので、
そのメソッドは必ずオーバーライドする必要がある。

コード

trait Programmer {
  def write = println("コードを書きます")
}

trait Writer {
  def write = println("記事を書きます")
}

// このまま書くとerror: class Person inherits conflicting members:とかなる
// class Person extends Programmer with Writer
class Person extends Programmer with Writer {
  // なのでwriteメソッドをオーバーライドする必要がある
  override def write = println("ドキュメントを書きます")
}


object Write {
  def main(args: Array[String]) {
    var p = new Person
    println(p)
    println(p.write)
  }
}

トレイトでsuper

superを利用してトレイトのwriteを呼び出す。

trait Programmer {
  def write = println("コードを書きます")
}

trait Writer {
  def write = println("記事を書きます")
}

class Person extends Programmer with Writer {
  override def write = super.write
}


object Write {
  def main(args: Array[String]) {
    var p = new Person
    println(p)
    println(p.write)
  }
}
$ scalac write.scala
$ scala Write
Person@46fde259
記事を書きます

abstract override

abstract宣言されたメソッドの中でsuperの呼び出しを行っている。 この場合、メソッドの具体的な定義がしてあるクラスやトレイトの後で ミックスインされているのであれば正しく動く。

定義内容が動的に束縛される。

こういう処理をやるためにはabstract overrideを使う。

abstract class Engineer {
  println ("class Engineer constructor")

  def work(time:Int)
}

class Person extends Engineer {
  println ("class Person constructor")

  def work(time:Int) {
    println ("Person#work start")
    println ("1つのタスクを"+time+"分で行います")
    println ("Person#work end")
  }
}

trait Programmer extends Engineer {
  println("trait Programmer constructor")

  abstract override def work(time:Int) = {
    println("Programmer#work start")
    super.work(time - 15)
    println("Programmer#work end")
  }
}

object Engineer {
  def main(args: Array[String]) {
    var p1 = new Person
    println(p1.work(60))
    var p2 = new Person with Programmer
    println(p2.work(60))
  }
}

workメソッドを呼ぶとProgrammerトレイトのworkメソッドを呼び、そのあとにPersonクラスのworkを実行する。

$ scala Engineer
class Engineer constructor
class Person constructor
Person#work start
1つのタスクを60分で行います
Person#work end

class Engineer constructor
class Person constructor
trait Programmer constructor
Programmer#work start
Person#work start
1つのタスクを45分で行います
Person#work end
Programmer#work end

トレイトの順番

abstract class Engineer {
  println ("class Engineer constructor")

  def work(time:Int)
}

class Person extends Engineer {
  println ("class Person constructor")

  def work(time:Int) {
    println ("Person#work start")
    println ("1つのタスクを"+time+"分で行います")
    println ("Person#work end")
  }
}

trait Programmer extends Engineer {
  println("trait Programmer constructor")

  abstract override def work(time:Int) = {
    println("Programmer#work start")
    super.work(time - 15)
    println("Programmer#work end")
  }
}

trait Agiler extends Engineer {
  println("trait Agiler constructor")

  abstract override def work(time:Int) = {
    println("Programmer#work start")
    super.work(time / 2)
    println("Programmer#work end")
  }
}

object Engineer {
  def main(args: Array[String]) {
    var p4 = new Person with Programmer with Agiler
    println(p4.work(60)) // (60/2)-15
    var p3 = new Person with Agiler with Programmer
    println(p3.work(60)) // (60-15)/2
  }
}

型のパラメータ化

一般的にはコンストラクタやメソッドを使用するとき、引数を使用してパラメータ化する

型のパラメータ化とは、それと同じようにクラスやメソッドなどで使用する型そのものをパラメータ化再利用性を高める機能である。

型パラメータ名を指定していなくても型推論でString型だったりAny型にしたりできる。

型パラメータをString型に指定しておいてString型以外の要素を渡そうとするとコンパイルエラーにできる。

elcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_45).
Type in expressions to have them evaluated.
Type :help for more information.

scala> val sList = List[String]("a","b","c")
sList: List[String] = List(a, b, c)

scala> val sList = List("a","b","c")
sList: List[String] = List(a, b, c)

scala> sList.head
res0: String = a

scala> val sList = List("a","b",1)
sList: List[Any] = List(a, b, 1)

scala> val sList = List[String]("a","b",1)
<console>:7: error: type mismatch;
 found   : Int(1)
 required: String
       val sList = List[String]("a","b",1)
                                        ^

型パラメータを使ったクラスのインスタンス化

下の例だとMySampleのparamフィールドはString型として使えるようになる。

class MySample[A] {
  var param:A = _ // 型パラメータの型を指定する
  def get:A = param
  def set(param:A) = this.param = param
}

object Sample {
  def main(args: Array[String]) {
    val x = new MySample[String]
    x.set("hello")
    println(x.get)
  }
}