decadence

個人のメモ帳

Tips07 (def/val, pf, call-by-name, 変位, 境界, assert)

自分用のメモ -> Tipsという名の考察とコピペ

defとvalの疑問に対しては,twitterで色々紹介して頂きました.
再度,この場を借りて感謝の意を.

同時刻に遅延評価について色々言及があって面白そうだった.

defとvalは違う

  • >結論 : どちらを使うとか現時点で理由付けを断言出来ないけど,なんとなく気持ち分かるから保留

いやしかし,なんやこれ…
評価のタイミングが変わるのかな...

scala> def a = { println("a"); 10 }
a: Int
scala> val b = { println("b"); 10 }
b
b: Int = 10

Scala def versus val - Stack Overflow

関数定義時(関数オブジェクト定義時?)いきなり引数をパターンマッチしたり出来る.(ここでは後述のようなPartialFunctionを使うべきか)

scala> val g:Int => Int = {
     | case s if (s%2 == 0) => s*10
     | case s => s
     | }
g: Int => Int = <function1>
scala> g(4)
res115: Int = 40

ちなみにこれdefでも書ける.

defで定義された関数について

scala> def c = (x: Int) => x + 1
c: Int => Int <function1>
scala> def d(x: Int) = x + 1
d: (x: Int)Int

メソッド != オブジェクト - プログラミング言語Scala 日本語情報サイト

dのような形で定義された関数はファーストクラスオブジェクトではない
d _ とすればdの関数オブジェクトが取り出せる.
ちなみに関数オブジェクトが期待されてる場所でf(d)とした際には,implicit conversionにより自動的にdの関数オブジェクトとなる
getClassをするとcはclass $anonfun$c$1となるが,dの存在は謎.一体何なんだろうか.

PartialFunction

isDefinedAtが自動で定義される

val pf:String --> Option[String] = { case s if s == null || s == "" => None; case s => Some(s) }
list.collect(pf)

call-by-name

引数を遅延評価する

def foo(f: Unit) { println("before"); f; println("after") }
foo(println("Hello"))  // Hello, before, after と出力 : call-by-value
def foo(f: => Unit) { println("before"); f; println("after") }
foo(println("Hello"))  // before, Hello, after と出力 : call-by-name

CBV(call-by-value)は引数を"先に"評価する => 各引数を一度しか評価しないで済む利点
CBN(call-by-name)は"使用時に"引数を評価 => 使わない引数を評価しないで済む利点

forでパターンマッチ

scala> List(Some(1), None, Some(5), None, Some(3))
res82: List[Option[Int]] = List(Some(1), None, Some(5), None, Some(3))
scala> for(Some(v) <- res82) println(v)
1
5
3

変位指定 -> nonvariantからcovariantにする

[+T] : Tの子クラスも代入出来る
[-T] : Tの親クラスも代入出来る

型パラメータの境界

[T <: A] : 上限境界
[T >: A] : 下限境界
[T >: A

型パラメータの制約

A =:= B : AとBが等しい。
A

Structural Subtyping

型は定義しても継承関係までは定義したくない,その時々で適当なインターフェースを割り振るように出来たら良いという考え方.
あるメソッドのシグニチャ(名前、引数の例えば{def mkString (start:String, sep:String, end:String):String}というシグニチャを持つ型Aを定義すると、上記のシグニチャを持つ型Bや型CはAの派生型と見なされるわけです。
このように、2つの型がもつメソッドなどの構造によって派生関係が決まるのがStructural Subtyping(構造的部分型)というものです。対して、通常のextendsなどの宣言によって派生関係を決定するのはNominal Subtyping(公称型)といいます。
(皿うどん)Structural Subtyping(構造的部分型)アレコレ - ( ꒪⌓꒪) ゆるよろ日記

エラー・アサーション

scala.Predef
sys.error("hoge")
assert(a == b, "hoge") // AssertionError
require(a == b, "hoge") // IllegalArgumentException : 引数チェックに使用する