これがわかるとshapelessのコードも読めるかもしれない
TRANSCRIPT
Who?
● 教育学部数学科 出身
● @busterdayo● サーバーサイドエンジニア at Tamecco
Agenda
● ペアノの公理
● 自然数 - オブジェクト
● 自然数 + 加法 - オブジェクト
● 自然数 + 加法 - 型● 応用例 - N次元ベクトル
● Def macro● Dynamic
ペアノの公理 - wikipedia調べ
自然数は次の5条件を満たす。
● 自然数 0 が存在する。
● 任意の自然数 a にはその後者 (successor)、suc(a) が存在する(suc(a) は a + 1 の "意味")。
● 0 はいかなる自然数の後者でもない(0 より前の自然数は存在しない)。
● 異なる自然数は異なる後者を持つ:a ≠ b のとき suc(a) ≠ suc(b) となる。
● 0 がある性質を満たし、a がある性質を満たせばその後者 suc(a) もその性質を満
たすとき、すべての自然数はその性質を満たす。
https://ja.wikipedia.org/wiki/ペアノの公理
自然数 + 加法 - オブジェクト
自然数の加法は再帰的に、以下のように定義できる。
● すべての自然数 a に対して、a + 0 = a● すべての自然数 a, b に対して、a + suc(b) = suc(a + b)https://ja.wikipedia.org/wiki/自然数
● すべての自然数 a に対して、零 + a = a● すべての自然数 a, b に対して、後者(b) + a = 後者(a + b)
自然数 + 加法 - オブジェクト
sealed trait 自然数 { def +( n: 自然数 ) : 自然数
}object 零 extends 自然数 { def +( a: 自然数 ): 自然数 = a // 零 + a = a}case class 後者(b: 自然数) extends 自然数 { def +( a: 自然数 ): 自然数 = 後者( a + b ) // 後者(b) + a = 後者(a + b)
}
証明: 0 + a = a ------> 公理1後者(a) + b = 後者(a + b) ------> 公理2は公理として扱う。(証明なしで正しいものとして扱う)
以下が正しいことを証明する。
a + 0 = a → n1a + 後者(b) = 後者(a + b) -> n2----数学的帰納法 を使う
n1の証明
* a = 0 の時
0 + 0 = 0 -----> 公理1 より
* a = k の時
k + 0 = k が成り立つと仮定 ---> 仮定1* a = 後者(k)後者(k) + 0 = 後者(k + 0) -----> 公理2より
= 後者(k) -----> 仮定1 より
n2 の証明:* a = 0の時0 + 後者(b) = 後者(b) ---> 公理2より = 後者(0 + b) ---> 公理1より
* a = k の時k + 後者(b) = 後者(k + b) → 仮定2
* a = 後者(k)の時後者(k) + 後者(b) = 後者(k + 後者(b)) = 後者(後者(k + b)) ---> 仮定2 = 後者(後者(k) + b) ---> 公理2
1 + 1 = 2は当たり前?
object 零 extends 自然数 { def +( a: 自然数 ): 自然数 = a}case class 後者(b: 自然数) extends 自然数 { def +( a: 自然数 ): 自然数 = 後者( a + b ) }
object 零 extends 自然数 { def +( a: 自然数 ): 自然数 = a}case class 後者(b: 自然数) extends 自然数 { def +( a: 自然数 ): 自然数 = a match { case 後者(c) => 後者(c +b) case 零 => 後者(b) }}
代数学 - 群,環,体
*http://d.hatena.ne.jp/Zellij/20121211/p1
Swiftで代数学http://qiita.com/taketo1024/items/bd356c59dc0559ee9a0b
自然数 + 加法 - 型
sealed trait 自然数 { def +( n: 自然数 ) : 自然数
}object 零 extends 自然数 { def +( a: 自然数 ): 自然数 = a }case class 後者(b: 自然数) extends
自然数 { def +( a: 自然数 ): 自然数 = 後者( a + b ) }
sealed trait 自然数 { type 足す[N <: 自然数] <: 自然数
}trait 零 extends 自然数{ override type 足す[N <: 自然数] = N}trait 後者[N<:自然数] extends 自然数 { override type 足す[O <: 自然数] = 後者[N#足す[O]]}
応用例 - N次元ベクトル trait
sealed trait ベクトル集合[次元数 <: 自然数] { def +( vector: ベクトル集合[次元数] ): ベクトル集合[次元数] def ++[任意の次元数 <: 自然数]( vector: ベクトル集合[任意の次元数] ): ベクトル集合[次元数#足す[任意の次元数]]}
N次元ベクトル - 零次元ベクトル
case object 零次元ベクトル extends ベクトル集合 [零] { def +( vector: ベクトル集合 [零] ): ベクトル集合 [零] = 零次元ベクトル
def ++[任意の次元数 <: 自然数]( vector: ベクトル集合 [任意の次元数] ): ベクトル集合 [零#足す[任意の次元数]] = vector}
N次元ベクトル - 一次元以上
case class ベクトル[残り個数 <: 自然数] ( 最初: Int, 残り: ベクトル集合 [残り個数] ) extends ベクトル集合 [後者[残り個数]] { def +( vector: ベクトル集合 [後者[残り個数]] ): ベクトル集合 [後者[残り個数]] = { vector match { case ベクトル( head, tail ) => ベクトル[残り個数]( 最初 + head, 残り + tail) } } def ++[Size <: 自然数]( vector: ベクトル集合 [Size] ): ベクトル集合 [後者[残り個数]#足す[Size]] = new ベクトル[残り個数#足す[Size]]( 最初, 残り.++( vector ) )}
Def macro def apply[次元数 <: 自然数]( numbers: Int* ): ベクトル集合[次元数] = macro ベクトルマクロ実装[次元数]
def ベクトルマクロ実装[個数 <: 自然数]( c: Context )(numbers: c.Expr[Int]*) = { import c.universe._ val succTpe = typeOf[後者[_]].typeConstructor val _0Tpe = typeOf[零] if ( numbers.isEmpty ) c.abort( c.enclosingPosition, "Need more than or equl to 1 Integer!!!" ) (numbers.foldRight((_0Tpe,q"""_root_.com.github.buster84.零次元ベクトル""": Tree)){ case ( literal, (numTpe, accTree )) => (appliedType(succTpe, numTpe), q"""new _root_.com.github.buster84.ベクトル[${numTpe}]( ${literal}, ${accTree})""") })._2 }
Dynamic - applyDynamicclass MyArray extends Dynamic { val a = Array("a1", "a2", "a3") val b = Array("b", "bb", "bbb") def applyDynamic(key: String)(index: Int): String = { key match { case "aAt" => a(index) case "bAt" => b(index) case _ => "" } }}
scala> val arr = new MyArrayarr: MyArray = MyArray@19e2223
scala> arr.aAt(1)res29: String = a2
scala> arr.bAt(1)res30: String = bb
scala> arr.zAt(0)res31: String = ""
* 参考: http://www.ne.jp/asahi/hishidama/home/tech/scala/dynamic.html
Dynamic - applyDynamic + macrodef applyDynamic(method: String)(numbers: Int*): Any = macro forwardToApplydef forwardToApply(c: Context)(method: c.Expr[String])(numbers: c.Expr[Int]*) = {
import c.universe._ val succSym = typeOf[後者[_]].typeConstructor.typeSymbol val _0Sym = typeOf[_0].typeSymbol def loop(i: Int, acc: Tree): Tree = { if(i == 0) acc else loop(i-1, AppliedTypeTree(Ident(succSym), List(acc))) }
val numTypeTree = loop(size, Ident(_0Sym)) val numbersTree = numbers.map(_.tree).toList Apply(TypeApply(Select(Ident(TermName("ベクトル")), TermName("apply")), List(numTypeTree)), numbersTree)
}https://github.com/buster84/Natural/blob/master/src/main/scala/com/github/buster84/ベクトル.scala
References
https://github.com/milessabin/shapeless
https://www.parleys.com/tutorial/type-level-programming-scala-101
http://downloads.typesafe.com/website/presentations/ScalaDaysSF2015/T4_Barnes_Typelevel_Prog.pdf
https://ja.wikipedia.org/wiki/自然数