℘ make now just

if you wanna break free you better listen to me

DecJanFebMarAprMayJunJulAugSepOctNov/post/2024-11-10-diary//post/2024-11-11-diary//post/2024-11-12-diary//post/2024-11-13-diary//post/2024-11-14-diary//post/2024-11-15-diary//post/2024-11-16-diary//post/2024-11-17-diary//post/2024-11-18-diary//post/2024-11-19-diary//post/2024-11-20-diary//post/2024-11-21-diary//post/2024-11-22-diary//post/2024-11-23-diary//post/2024-11-24-diary//post/2024-11-25-diary//post/2024-11-26-diary//post/2024-11-27-diary//post/2024-11-28-diary//post/2024-11-29-diary//post/2024-11-30-diary//post/2024-12-01-diary//post/2024-12-02-diary//post/2024-12-03-diary//post/2024-12-04-diary//post/2024-12-05-diary//post/2024-12-06-diary//post/2024-12-07-diary//post/2024-12-08-diary//post/2024-12-09-diary//post/2024-12-10-diary//post/2024-12-11-diary//post/2024-12-12-diary//post/2024-12-13-diary//post/2024-12-14-diary//post/2024-12-15-diary//post/2024-12-16-diary//post/2024-12-17-diary//post/2024-12-18-diary//post/2024-12-19-diary//post/2024-12-20-diary//post/2024-12-21-diary//post/2024-12-22-diary//post/2024-12-23-diary//post/2024-12-24-diary//post/2024-12-25-diary//post/2024-12-26-diary//post/2024-12-27-diary//post/2024-12-28-diary//post/2024-12-29-diary//post/2024-12-30-diary//post/2024-12-31-diary//post/2025-01-01-diary//post/2025-01-02-diary//post/2025-01-03-diary//post/2025-01-04-diary//post/2025-01-05-diary//post/2025-01-06-diary//post/2025-01-07-diary//post/2025-01-08-diary//post/2025-01-09-diary//post/2025-01-10-diary//post/2025-01-11-diary//post/2025-01-12-diary//post/2025-01-13-diary//post/2025-01-14-diary//post/2025-01-15-diary//post/2025-01-16-diary//post/2025-01-17-diary//post/2025-01-18-diary//post/2025-01-19-diary//post/2025-01-20-diary//post/2025-01-21-diary//post/2025-01-22-diary//post/2025-01-23-diary//post/2025-01-24-diary//post/2025-01-25-diary//post/2025-01-26-diary//post/2025-01-27-diary//post/2025-01-28-diary//post/2025-01-29-diary//post/2025-01-30-diary//post/2025-01-31-diary//post/2025-02-01-diary//post/2025-02-02-diary//post/2025-02-03-diary//post/2025-02-04-diary//post/2025-02-05-diary//post/2025-02-06-diary//post/2025-02-07-diary//post/2025-02-08-diary//post/2025-02-09-diary//post/2025-02-10-diary//post/2025-02-11-diary//post/2025-02-12-diary//post/2025-02-13-diary//post/2025-02-14-diary//post/2025-02-15-diary//post/2025-02-16-diary//post/2025-02-17-diary//post/2025-02-18-diary//post/2025-02-19-diary//post/2025-02-20-diary//post/2025-02-21-diary//post/2025-02-22-diary//post/2025-02-23-diary//post/2025-02-24-diary//post/2025-02-25-diary//post/2025-02-26-diary//post/2025-02-27-diary//post/2025-02-28-diary//post/2025-03-01-diary//post/2025-03-02-diary//post/2025-03-03-diary//post/2025-03-04-diary//post/2025-03-05-diary//post/2025-03-06-diary//post/2025-03-07-diary//post/2025-03-08-diary//post/2025-03-09-diary//post/2025-03-10-diary//post/2025-03-11-diary//post/2025-03-12-diary//post/2025-03-13-diary//post/2025-03-14-diary//post/2025-03-15-diary//post/2025-03-16-diary//post/2025-03-17-diary//post/2025-03-18-diary//post/2025-03-19-diary//post/2025-03-20-diary//post/2025-03-21-diary//post/2025-03-22-diary//post/2025-03-23-diary//post/2025-03-24-diary//post/2025-03-25-diary//post/2025-03-26-diary//post/2025-03-27-diary//post/2025-03-28-diary//post/2025-03-29-diary//post/2025-03-30-diary//post/2025-03-31-diary//post/2025-04-01-diary//post/2025-04-02-diary//post/2025-04-03-diary//post/2025-04-04-diary//post/2025-04-05-diary//post/2025-04-06-diary//post/2025-04-07-diary//post/2025-04-08-diary//post/2025-04-09-diary//post/2025-04-10-diary//post/2025-04-11-diary//post/2025-04-12-diary//post/2025-04-13-diary//post/2025-04-14-diary//post/2025-04-15-diary//post/2025-04-16-diary//post/2025-04-17-diary//post/2025-04-18-diary//post/2025-04-19-diary//post/2025-04-20-diary//post/2025-04-21-diary//post/2025-04-22-diary//post/2025-04-23-diary//post/2025-04-24-diary//post/2025-04-25-diary//post/2025-04-26-diary//post/2025-04-27-diary//post/2025-04-28-diary//post/2025-04-29-diary//post/2025-04-30-diary//post/2025-05-01-diary//post/2025-05-02-diary//post/2025-05-03-diary//post/2025-05-04-diary//post/2025-05-05-diary//post/2025-05-06-diary//post/2025-05-07-diary//post/2025-05-08-diary//post/2025-05-09-diary//post/2025-05-10-diary//post/2025-05-11-diary//post/2025-05-12-diary//post/2025-05-13-diary//post/2025-05-14-diary//post/2025-05-15-diary//post/2025-05-16-diary//post/2025-05-17-diary//post/2025-05-18-diary//post/2025-05-19-diary//post/2025-05-20-diary//post/2025-05-21-diary//post/2025-05-22-diary//post/2025-05-23-diary//post/2025-05-24-diary//post/2025-05-25-diary//post/2025-05-26-diary//post/2025-05-27-diary//post/2025-05-28-diary//post/2025-05-29-diary//post/2025-05-30-diary//post/2025-05-31-diary//post/2025-06-01-diary//post/2025-06-02-diary//post/2025-06-03-diary//post/2025-06-04-diary//post/2025-06-05-diary//post/2025-06-06-diary//post/2025-06-07-diary//post/2025-06-08-diary//post/2025-06-09-diary//post/2025-06-10-diary//post/2025-06-11-diary//post/2025-06-12-diary//post/2025-06-13-diary//post/2025-06-14-diary//post/2025-06-15-diary//post/2025-06-16-diary//post/2025-06-17-diary//post/2025-06-18-diary//post/2025-06-19-diary//post/2025-06-20-diary//post/2025-06-21-diary//post/2025-06-22-diary//post/2025-06-23-diary//post/2025-06-24-diary//post/2025-06-25-diary//post/2025-06-26-diary//post/2025-06-27-diary//post/2025-06-28-diary//post/2025-06-29-diary//post/2025-06-30-diary//post/2025-07-01-diary//post/2025-07-02-diary//post/2025-07-03-diary//post/2025-07-04-diary//post/2025-07-05-diary//post/2025-07-06-diary//post/2025-07-07-diary//post/2025-07-08-diary//post/2025-07-09-diary//post/2025-07-10-diary//post/2025-07-11-diary//post/2025-07-12-diary//post/2025-07-13-diary//post/2025-07-14-diary//post/2025-07-15-diary//post/2025-07-16-diary//post/2025-07-17-diary//post/2025-07-18-diary//post/2025-07-19-diary//post/2025-07-20-diary//post/2025-07-21-diary//post/2025-07-22-diary//post/2025-07-23-diary//post/2025-07-24-diary//post/2025-07-25-diary//post/2025-07-26-diary//post/2025-07-27-diary//post/2025-07-28-diary//post/2025-07-29-diary//post/2025-07-30-diary//post/2025-07-31-diary//post/2025-08-01-diary//post/2025-08-02-diary//post/2025-08-03-diary//post/2025-08-04-diary//post/2025-08-05-diary//post/2025-08-06-diary//post/2025-08-07-diary//post/2025-08-08-diary//post/2025-08-09-diary//post/2025-08-10-diary//post/2025-08-11-diary//post/2025-08-12-diary//post/2025-08-13-diary//post/2025-08-14-diary//post/2025-08-15-diary//post/2025-08-16-diary//post/2025-08-17-diary//post/2025-08-18-diary//post/2025-08-19-diary//post/2025-08-20-diary//post/2025-08-21-diary//post/2025-08-22-diary//post/2025-08-23-diary//post/2025-08-24-diary//post/2025-08-25-diary//post/2025-08-26-diary//post/2025-08-27-diary//post/2025-08-28-diary//post/2025-08-29-diary//post/2025-08-30-diary//post/2025-08-31-diary//post/2025-09-01-diary//post/2025-09-02-diary//post/2025-09-03-diary//post/2025-09-04-diary//post/2025-09-05-diary//post/2025-09-06-diary//post/2025-09-07-diary//post/2025-09-08-diary//post/2025-09-09-diary//post/2025-09-10-diary//post/2025-09-11-diary//post/2025-09-12-diary//post/2025-09-13-diary//post/2025-09-14-diary//post/2025-09-15-diary//post/2025-09-16-diary//post/2025-09-17-diary//post/2025-09-18-diary//post/2025-09-19-diary//post/2025-09-20-diary//post/2025-09-21-diary//post/2025-09-22-diary//post/2025-09-23-diary//post/2025-09-24-diary//post/2025-09-25-diary//post/2025-09-26-diary//post/2025-09-27-diary//post/2025-09-28-diary//post/2025-09-29-diary//post/2025-09-30-diary//post/2025-10-01-diary//post/2025-10-02-diary//post/2025-10-03-diary//post/2025-10-04-diary//post/2025-10-05-diary//post/2025-10-06-diary//post/2025-10-07-diary//post/2025-10-08-diary//post/2025-10-09-diary//post/2025-10-10-diary//post/2025-10-11-diary//post/2025-10-12-diary//post/2025-10-13-diary//post/2025-10-14-diary//post/2025-10-15-diary//post/2025-10-16-diary//post/2025-10-17-diary//post/2025-10-18-diary//post/2025-10-19-diary//post/2025-10-20-diary//post/2025-10-21-diary//post/2025-10-22-diary//post/2025-10-23-diary//post/2025-10-24-diary//post/2025-10-25-diary//post/2025-10-26-diary//post/2025-10-27-diary//post/2025-10-28-diary//post/2025-10-29-diary//post/2025-10-30-diary//post/2025-10-31-diary//post/2025-11-01-diary//post/2025-11-02-diary//post/2025-11-03-diary//post/2025-11-04-diary//post/2025-11-05-diary//post/2025-11-06-diary//post/2025-11-07-diary//post/2025-11-08-diary//post/2025-11-09-diary//post/2025-11-10-diary/
  • Less
  • More

2019-09-19: implicit完全に理解した

やったこと

ミリシタ

TC最初のイベントのはじまり。
ちょっとだけやる気があるのだけど、目下の悩みはSSA。
あと2日とか実感がねえ。

シャニ

MVP取れた。
MVPのコミュ良かった。

https://twitter.com/make_now_just/status/1174629419610066945

今度は灯織で感謝祭していた。
ようやく星3ノートクリアできた。
しんどすぎるんじゃ。

https://twitter.com/make_now_just/status/1174638867267248128

https://twitter.com/make_now_just/status/1174640126384689154

daliのスライド

daliの開発はsbtがJDK 13で壊れた影響で完全に止まっている。
許せ‥‥。

というわけでスライドを公開した。

https://speakerdeck.com/makenowjust/dali-introduction

まあ大した内容ではないが。

implicit完全に理解した

迷ったときは仕様を読むと良い。

https://www.scala-lang.org/files/archive/spec/2.13/07-implicits.html#implicit-parameters

implicitな値の宣言がimplicitパラメータを持つとき、implicitな値は再帰的に探索されていく。
そこで見つかった型とその型を提供するimplicitな値の宣言はスタックに積まれる。
さらに、探索が無限ループに陥らないようにするため、スタックの状態によっては探索を打ち切る場合がある。
(探索を打ち切る=探索失敗ではないので注意)

  • スタックに積もうとしてる型と等しい型があって、その型のあるスタック上の位置と先頭までの間にby nameな宣言がある場合、スタックのそこまでをlazy valでくくり出して、成功で探索を打ち切る。
  • スタックに積もうとしてる型が支配する (dominateする)がスタック上にある場合、divergingとして失敗で探索を打ち切る。
  • それ意外の場合、スタックに型と宣言を追加して、探索を継続する。

で、この「支配する」という条件が曲者で、詳細は次のようになっている。

Tが型U支配するとはTUが等しいか、TUのトップレベルの型コンストラクタ(top-level type constructor)に等しい部分があり、TUよりも複雑で、TUのcovering setが等しいときのことをいう。

用語がいくつか出てきたのでさらに解説すると、

  • トップレベルの型コンストラクタとは簡単に言うと、型パラメタを除いたり、シングルトン型を本来の型に戻したりしたもののこと。
    例えばList[Int]ならトップレベルの型コンストラクタはListだし"foo"ならStringになる。
  • TUよりも複雑であるとは、型の複雑性(整数値)がより大きいことをいう。
    型の複雑性は簡単に言うと、エイリアスなどを全て展開した上で、型に現れるパッケージ以外の名前の数を重複混みで数えたものとして考えればいいと思う。ただしシングルトン型は+ 1する。
    例えばList[Int]List, Intなので複雑性は2List[(Int, String, Int)]List, Tuple3, Int, String, Intで複雑性は5、といった感じ。
  • 型のcovering setとは、型に現れるパッケージ以外の名前の集合でいいと思う。
    例えばList[(Int, Int)]のcovering setはList, Tuple2, Intのような感じ。

ここまで理解すると、昨日のTreeEqが導出できない理由が説明できる。

// List:
sealed trait List[A]
class Nil[A]
class Cons[A]

// Tree:
class Tree[A]

// HList:
sealed trait HList
class HNil extends HList
class :*:[H, T <: HList] extends HList

// Coproduct:
sealed trait Coproduct
class CNil extends Coproduct
class :+:[H, T <: Coproduct] extends Coproduct

// Generic:
trait Generic[A, R]

object Generic {
  implicit def list[A]: Generic[List[A], Nil[A] :+: Cons[A] :+: CNil] = ???
  implicit def nil[A]: Generic[Nil[A], HNil] = ???
  implicit def cons[A]: Generic[Cons[A], A :*: List[A] :*: HNil] = ???

  implicit def tree[A]: Generic[Tree[A], A :*: List[Tree[A]] :*: HNil] = ???
}

// Eq:
trait Eq[A]

object Eq {
  implicit def int: Eq[Int] = ???

  implicit def generic[A, R](implicit AR: Generic[A, R], R: GEq[R]): Eq[A] = ???
}

// GEq:
trait GEq[R]

object GEq {
  implicit val hnil: GEq[HNil] = ???
  implicit def hcons[H: GEq, T <: HList: GEq]: GEq[H :*: T] = ???
  implicit val cnil: GEq[CNil] = ???
  implicit def ccons[H: GEq, T <: Coproduct: GEq]: GEq[H :+: T] = ???

  implicit def value[A](implicit A: => Eq[A]): GEq[A] = ???
}

ここでimplicitly[Eq[Tree[Int]]]とすると、まずEq.genericを候補としてGEq[Int :*: List[Tree[Int]] :*: HNil]を探索しに行く。
探索が続くと最終的に、GEq[Cons[Tree[Int]]]の候補としてGEq.valueを見つけて、Eq[Cons[Tree[Int]]]を探索する。
この候補はEq.genericGEq[Tree[Int] :*: List[Tree[Int]] :*: HNil]を見つける必要があるが、ここで最初のGEq[Int :*: List[Tree[Int]] :*: HNil]と複雑度、covering setを比較すると、

  • GEq[Int :*: List[Tree[Int]] :*: HNil]の複雑度8、covering set GEq, :*:, HNil, List, Tree, Int
  • GEq[Tree[Int] :*: List[Tree[Int]] :*: HNil]の複雑度 9、 covering set GEq, :*: HNil, List, Tree, Int

なので、divergingと判定され探索が打ち切られ、候補が見つけられず全体の探索が失敗する。

一応、ここまで理解していれば回避策を考えるのも簡単で、例えばTuple1を追加してGeneric.treeを修正すれば、

// Tuple1:
class Tuple1[A]

// Generic:
object Generic {
  // ...

  implicit def tree[A]: Generic[Tree[A], Tuple1[A] :*: List[Tree[A]] :*: HNil]

  implicit def tuple1[A]: Generic[Tuple1[A], A :*: HNil]
}

implicitly[Eq[Tree[Int]]]は動くようになる。
これはTuple1で囲ったことでcovering setが異なるものになったため。
しかしTuple1[List[Tree[A]]]としてはいけない。
なぜなら、これだとEq[Tuple1[List[Tree[Int]]]]を導出するときに探索するGEq[List[Tree[Int]] :*: HNil]が、Eq[Cons[Tree[Int]]]を導出するときに探索するGEq[Tree[Int] :*: List[Tree[Int]] :*: HNil]に支配されてしまい、divergingになってしまう。

また次の定義を追加しても動作する。

implicit def list[A: Eq]: Eq[List[A]] = Eq.generic

この定義を追加することでEq[Cons[Tree[Int]]]の探索が行なわれず、先にEq[Tree[Int]]の探索が行なわれ、これは最初の型と等しく間にGEq.valueによるby nameな値を含むため、正しく展開される。

ちなみにimplicitlyの展開結果などはreifyを使うと比較的簡単に確かめられる。
覚えておくと便利かもしれない。

import scala.reflect.runtime.universe.reify

println(reify(implicitly[Eq[Tree[Int]]]))
// Expr[Eq[Tree[Int]]](Predef.implicitly[Eq[Tree[Int]]]({
//   final class LazyDefns$1 {
//     final val rec$1 = Eq.generic(
//       Generic.tree,
//       GEq.hcons(
//         GEq.value(Eq.int),
//         GEq.hcons(
//           GEq.value(list(rec$1)),
//           GEq.hnil,
//         ),
//       ).
//     )
//   };
//   final val lazyDefns$1 = new LazyDefns$1();
//   lazyDefns$1.rec$1
// }))

上のはlistを定義したときの展開結果だけど、Tuple1を使うと以下のようになる。
いかにも完全に展開しました、という雰囲気がある。

println(reify(implicitly[Eq[Tree[Int]]]))
// Expr[Eq[Tree[Int]]](Predef.implicitly[Eq[Tree[Int]]]({
//   final class LazyDefns$1 {
//     final val rec$2 = GEq.hcons(
//       GEq.value(
//         Eq.generic(
//           Generic.list,
//           GEq.ccons(
//             GEq.value(Eq.generic(Generic.nil, GEq.hnil)),
//             GEq.ccons(
//               GEq.value(Eq.generic(Generic.cons, GEq.hcons(GEq.value(rec$1), rec$2))),
//               GEq.cnil,
//             ),
//           ),
//         ),
//       ),
//       GEq.hnil,
//     );
//     final val rec$1 = Eq.generic(
//       Generic.tree,
//       GEq.hcons(
//         GEq.value(Eq.generic(Generic.tuple1, GEq.hcons(GEq.value(Eq.int), GEq.hnil))),
//         rec$2,
//       ),
//     )
//   };
//   final <synthetic> val lazyDefns$1 = new LazyDefns$1();
//   lazyDefns$1.rec$1
// }))

ただ、Tuple1を使う方法だとTree[List[Int]]では展開が上手くいかないのでEq.genericを使ってEq[List[A]]を定義しておく方が無難な気がする。
(Eq[Tuple[List[Int]]]を導出するために探索するGEq[List[Int] :*: HNil]が、Eq[Cons[Int]]を導出するために探索するGEq[Int :*: List[Int] :*: HNil]に支配されてしまうため)

implicitへの理解度は上がったが、この知識がどこで役に立つのかは全く分からない。
あとScastie便利。


2019-09-20: JDK13でScala無理なのでは

2019-09-19: implicit完全に理解した

2019-09-18: daliをリリースした