「入門 老眼」が出版されるのを待ってます
— magnoliak🍧 (@magnolia_k_) 2021年8月19日
老眼鏡の選び方から、最適なディスプレイの解像度設定など、きっと必要な知見はたくさんあるに違いない
とりあえずこれ読み直そうhttps://t.co/m57AydGo8w
— magnoliak🍧 (@magnolia_k_) 2021年8月19日
「入門 老眼」が出版されるのを待ってます
— magnoliak🍧 (@magnolia_k_) 2021年8月19日
老眼鏡の選び方から、最適なディスプレイの解像度設定など、きっと必要な知見はたくさんあるに違いない
とりあえずこれ読み直そうhttps://t.co/m57AydGo8w
— magnoliak🍧 (@magnolia_k_) 2021年8月19日
2021/8/15: 最初の言説のところ、微妙に何が何だかって記述だったので少し見直しました。
昔初めてPMBOKで「段階的詳細化」って用語を知った時、随分と当たり前のことにわざわざ名前がついてるんだなぁと思ったことが有るけど、案外ちゃんと名前をつけてあげないと最初から細部まで完璧な計画が(実際に有るかは別として)存在せねばならぬ、みたいな発想が(無自覚に)有る人に有効なんだなって
— magnoliak🍧 (@magnolia_k_) 2021年8月14日
PMBOK、計画を立てろ!って書いてるけど、その計画の精度については言って無くて、変えるべき時にちゃんと検証と承認しようねってしか言ってないんだよね
— magnoliak🍧 (@magnolia_k_) 2021年8月14日
初手で完璧で詳細な計画を立てろなんて言ってない
「システム開発は最後まで分からない、常に変更が続くのだ!だから詳細な事前の計画は無意味、やってみないと分からない!」という言説があり、まぁそうだなーと思う反面、個人的な活動ならばそれでいいけど、それなりのステークホルダーが存在する事業の場合は、「見通し」が無いと投資できませんって話にもなる。
結局計画である以上は常に未来の不確定さに、一定のリスクがあるわけで、「完全完璧な計画を求める人」も、「やってみないと分からないと言う人」も、どっちもその不確実さが自分に降りかかることを忌避して、リスクコントロールをしない人にも見える。
アジャイルは無計画ではなく、「計画をするタイミング、詳細度」をコントロールする方法論だと理解していて、「Perlがスコープをコントロールする言語」なのと同じくらい直感的でなく、一回やってみないと分からないけど、非常に実務的な発想だな、とも思う。
少し話は変わって、「その日やることをその日計画する」のと、「その日やることを前日までに計画する」では同じ計画でも意味合いが違ってくると思っていて、「その日やることをその日計画する」というのは得手して「やれることをやる」に陥りがちになる。一方で「その日やることを前日までに計画する」は、「やるべきことをやる」がやり易いやり方だと理解している。
それは計画に対する解像度の違いで、「やれることをやる」の場合、ゴールに向かうために、抜き差しする要素が限定されてしまうのに対して、「やるべきことやる」の場合、要素の抜き差しができるからだ。つまり、「余計なことはやらない」。
「余計なことはやらない」と言っても、単純に「止めちゃえばよかった」なんてことはあんまり無くて、「止めるなりの準備や、調整」が有って初めてやめられる。「止めるために新たにやらないといけないこと」が出てくるわけで。
計画の粒度、どこまでできていれば納得するかは、極めて個人の経験や資質、組織文化に由来することなので、絶対的な正解が有るわけではないけど、「計画の解像度を上げていく」という行為に意識的になっていくといいんじゃないかと思った全然まとまりの無い話。
追加
でも「計画を変える計画」が予めプロセスに組み込まれていないと、そうはならないわけで、「絶対に計画を見直す」というフェーズをちゃんと定義した、という意味でアジャイルは偉い
— magnoliak🍧 (@magnolia_k_) 2021年8月14日
「計画を変えること」に対する心理的な抵抗感はどこから来るかと言えば「説明するのが面倒」な訳で、「言ってくれれば承認するよ」は、論点が違うじゃないか、というね
— magnoliak🍧 (@magnolia_k_) 2021年8月14日
自分で初めて計画らしい計画を作ったとき、「とっかかり」がなさすぎて、まったく手が動かなかったけど、そんなにみんなが根拠を持って計画を書いている訳ではないんだなって分かってすっきりした
— magnoliak🍧 (@magnolia_k_) 2021年8月14日
書いてみて初めて対象に対する理解の解像度が上がるんだから、まず書こうっていう
だって未来の話だしね
Scala2におけるType Lambdaについては、下記のブログエントリが詳しい。
最初に、型パラメータの数を一つとして定義していると、型パラメータを二つ取る物を渡せない。
scala> trait Functor[F[_]] trait Functor scala> type F1 = Functor[Option] type F1 scala> type F2 = Functor[List] type F2 scala> type F3 = Functor[Map] ^ error: Map takes 2 type parameters, expected: 1
Mapが取る二つの型のうち、一つが決まれば、残るは一つなので大丈夫。
scala> type IntKeyMap[A] = Map[Int, A] type IntKeyMap scala> type F3 = Functor[IntKeyMap] type F3
ただし、いちいち途中の階層の型を定義するのは面倒くさい。
そこで、無名の型を定義して、その中で一つの型を確定させ、その型を返す方法が発明された。これなら1行で済むし、余計な命名も不要になる。
scala> type F5 = Functor[({ type T[A] = Map[Int, A] })#T] type F5
でも何をやっているのかわかりづらい。
そこで、Scala3には専用の構文(=>>
)が導入された。だいぶ謎記号が減ったScalaだけど、ここに来て一つ増えた。
scala> type F6 = Functor[ [A] =>> Map[Int, A] ] // defined alias type F6 = Functor[[A] =>> Map[Int, A]]
Scala2の時のtype lambdaの書き方をすると、対応が分かりやすい。
scala> type F7 = Functor[({ type T[A] = Map[Int, A] })#T] // defined alias type F7 = Functor[[A] =>> Map[Int, A]]
型のカリー化もできるそうだ。
type TL = [X] =>> [Y] =>> (X, Y)
型パラメータが得られば、こんな指定もできる。
scala> def foo[A[_,_],B](functor: Functor[({type AB[C] = A[B,C]})#AB]) = ??? def foo[A[_$3, _$4], B](functor: Functor[[C] =>> A[B, C]]): Nothing scala> def foo[A[_,_],B](functor: Functor[ [C] =>> A[B, C]]) = ??? def foo[A[_$1, _$2], B](functor: Functor[[C] =>> A[B, C]]): Nothing
ライブラリを作る人でなければ、このような汎用性のための機能はいらないかもしれないけど。
あと、これらのコードを動かしている最中に、aliasの挙動がよく分からなくなったけど、良い記事を見つけた。
技術書なんて必要なところを拾い読みするか、読書会でいろんな人の考え方や経験を知るきっかけに使うもの...慣れてくるとそんな感覚になってきますが、せっかくの夏休みなので初心に帰って、全部頭から再度まで読み切って、かつコードの写経もやってみて…というのをじっくりやるのもいいかもしれません。
そんな時には、できれば改めて基礎からじっくり学ぶ系の本が良いので、『アンダースタンディング コンピュテーション』などは如何でしょうか。
出版されたのは2014年ともう時間もけっこう経っていますが、「そもそもプログラミング言語って何だ?」「計算機って何だ?」「っていうか、ここで言う計算って何だ?」という問いかけに丁寧に答えてくれる1冊になっています。つまり、普段なかなか真正面から学ぶ機会のない、コンピューサイエンスで学ぶことのうちの一つですね。
特に前半の、Rubyを使ってプログラミング言語を実装する部分は単に写経するだけでも、構造が見えて学びが多いです。というか、絶対に写経した方がいいですね、わかった気になって単に読み進めていくと、「あれ、全然分からなくなった...」という瞬間がやっていきます。
中盤の、オートマトンから正規表現も、普段なにげなく使っている正規表現がどのような理論の上で構築されているのか、実際に動くプログラムで実感することができます。
後半の「第II部 計算と計算可能性」はかみごたえが有るというか、毎回自分も途中で挫折してしまうのですが、じっくり読んで理解を進めていく機会には、このくらいの難易度が欲しいですね。
というわけで、残念ながら自由に外にも出かけられない夏休み、クーラーの効いた部屋でじっくり技術書を、「考え、実行しながら」読み進めて、考えを深めるのはいかがでしょうか?
Scalaではclassの定義時にtraitをmix-inできる。
scala> trait A // defined trait A scala> class B extends A // defined class B scala> val o1 = new B val o1: B = B@36b53f08
この時、変数の型はBと推論されている。
また、オブジェクトの生成時にもmix-inできる。この時の型は先ほどと異なる結果となる。
scala> class C // defined class C scala> val o2 = new C with A val o2: C & A = anon$1@5486ee92
この時の型はScala3から導入されたIntersection型により、変数はCとAを同時に持つ型として推論されている。
変数定義だけでなく、当然引数の型の宣言でも使える。
scala> def method(obj: A & C) = println(obj.toString) def method(obj: A & C): Unit scala> method(o2) repl$.rs$line$6$$anon$1@5486ee92
Intersectionには型の継承関係が整理されているので、詳しくは公式ドキュメントを見ると良い。
Scala2の時は、Compound Typeという型で推論されていた。
scala> trait A defined trait A scala> class C defined class C scala> val o = new C with A o: C with A = $anon$1@ecd379a
もちろん明示的に指定できる。
scala> val o2: C with A = new C with A o2: C with A = $anon$1@22c7ef94
この変数の型におけるwithを使ったCompound Typeの記法は将来は廃止される予定であるとされている。
Scala3で明示的に指定してもIntersectionで置き換えられている。
scala> val o4: A with C = new C with A val o4: A & C = anon$1@799971ac
case classではない、通常のクラスでもapplyメソッドを持つコンパニオンオブジェクトが自動生成されるようになったので、newキーワードを使わなくてもオブジェクト生成ができるようになった。
scala> case class Person(name: String, age: Int) // defined case class Person scala> Person("Mike", 42) val res0: Person = Person(Mike,42) scala> class Company(name: String) // defined class Company scala> Company("ANAHEIM ELECTRONICS") val res1: Company = Company@3253d771
toString
メソッドが再定義されているわけではないので、オブジェクトのダンプの見え方は従来と変わらない。
Scala3対応の第5版。日本ではScala 2.13対応の第4版が出たばかりですが、原著はScala3対応となりました。
以前と構成も変わった箇所も多いですが、すべてのサンプルコードがScala3のquite style(要はpythonっぽいインデントベースの記法)になっていたり、implicit系の機能が全てScala3のgivenやusing、extensionといったキーワードに置き換わってところが特徴です。
新しい機能には比較的「これはScala3からの機能です」と書かれていますが、説明なしに解説が始まっている機能も有り、「絶対にScala3のソースしか読まない!書かない!」という方には良いのですが、Scala2ベースのソースが消えてなくなる訳でもないので、とまどうかもしれないですね。
というわけで、しばらくは、Scala2に入門する方が多いと思うので、今からScalaへ入門する方は第4版の翻訳版の方をお勧めします。