なんとなく、Windows の git bash の設定に見慣れてしまったので、Linux 上でも。
source ~/.git-prompt.sh export PS1='\[\e[1;32m\]\u@\h\[\e[m\] \[\e[1;33m\]\w\[\e[m\] \[\e[1;36m\]$(__git_ps1 " (%s)")\[\e[m\]\n\$ '
今日は、仕掛中の 023 を継続。スーパークラスをもつクラスを扱えるようにして、 mycompare4.hs が通るようになった。
クラス宣言のリネームでスーパークラスを捨ててしまっていたのをなおしたり、 runtime における辞書が多重継承できないのを直す必要があったり、なかなか面白かった。
この過程でみつけた他の不具合については、別イシューを立てたので、次は、 以下のように進めるのがいいのではないかな。
023ができたら、各インスタンスの定義を minimum complete definition にして、 余計なコードは消そう。
在宅勤務で、通勤時間がへったのと、リモートワークのために自宅のPC環境を整えたせいか、 すこし進捗するようになった。
これは難しいかもと思われた 009 がクリアできたのがうれしい。 やっぱり thih の Typing モジュールは間違っていなかった。
残りの Issues に関する覚書:
001, 002, 020, 022 あたりは、型に関するエラーなんだけど、原因にめぼしがついてない。
#004 を直した。 なまえに qualifier がついていたときの処理などはあとまわし。
これをやったので、つぎは adt-sample4.hs を通るようにできるとおもう(003)。
adt-sample2.hs がエラーになる(そして Int を Integer に変えると通る)理由を 考えてみる。
最初に疑ったのは、整数リテラルの方を Integer 決め打ちにしてしまっていないか (本来は Num t => t) だったが、これはシロだった。 整数リテラルは、Rename によって Lit (Litint i) に変換されるが、 Typing における tiLit (LitInt _) をみれば正しい型が付けられているのがわかる。
つぎに、Types をみると、以下があやしい:
tInt :: Type tInt = TCon (Tycon "Int" Star) tInteger :: Type tInteger = TCon (Tycon "Prelude.Integer" Star)
ここは、Int も Prelude.Int に直しておく。
つぎに、Num クラスのインスタンスに Prelude.Int もなっているかなぁという目でみていると、 Typing の以下のところが怪しい:
numClasses :: [Id] numClasses = ["Prelude.Num", "Prelude.Integral", "Prelude.Floating", "Prelude.Fractional", "Prelude.Integer", "Prelude.Real", "Prelude.RealFloat", "Prelude.RealFrac"]
ここに、"Prelude.Int", も加えれば、ひとまず通るようにはなるのかな…と思ったら、ならず。
原典(Typing Haskell in Haskell) を確認すると、ここには "Integer" もいらなかった。 あれー、なんで加えたんだ?
とりあえず、ただしく、取り除いておいた。
numClasses :: [Id] numClasses = ["Prelude.Num", "Prelude.Integral", "Prelude.Floating", "Prelude.Fractional", "Prelude.Real", "Prelude.RealFloat", "Prelude.RealFrac"]
じゃぁ、いったいどこで Integer だけを Num クラスにいれて、 Int をいれていないんだろう?とおもって、app/Main.hs からたどっていくと…
initRnState :: RnState initRnState = let ifxenv = insert "Prim.:" (Fixity RightAssoc 5) Symbol.empty in RnState { rnModid = "" , rnLvs = [] , rnTenv = Symbol.empty , rnIfxenv = ifxenv , rnCe = initialEnv -- preludeClasses , rnCms = primConsMems , rnKdict = Symbol.empty , rnCdicts = [] , rnConsts = emptyConstInfo }
あれ、preludeClasses はコメントアウトされていて、initialEnv にかわってる (ってことは、preludeClasses は未使用なのか)。
そうだ。lib/Prelude.hs をまずコンパイルするようにしてた(わすれてた)。
それでも、まだ adt-sample2.hs は通らない(また別のエラーに)が、make check は通ったので、ひとまず、今日はこんなところか。
x :: Integer と x :: Int の違いを比べる、もっと単純なテストケースをつくって追ったほうがよさそう。
⇒ intinteger[1-2].hs をつくったが、これらは通ってしまった。adt-sample2.hs がエラーするのは別の理由らしい。
adt-sample2.hs をエラーが再現する最小まで縮めた: atd-sample2x.hs
自作コンパイラの制作ノートを久々にひらく。前回なにか記入したのが 2019年3月4日なので一年ぶり以上だが、その前もまた1年ちかくあいていたり。 完全な放置プロジェクトになってた。
ほそぼそとでも再開しよう。
このモジュールは、Parser の出力する抽象構文 (Absyn) を変換して、型推論可能な形にする。 主な仕事は以下の通り:
…なのだが、このフェーズでは、上記以外に行わねばならないこととして、型やクラス、データ宣言の処理がある。 これらについては積み残しとなっていて、以前書いた記事 でも全く述べていない。
しばらくは、この Rename.hs モジュールに手をくわえながら、解説メモ を書いていくことにする。
久々にみたノートの記述からみると、未処理の宣言のうち DataDecl(抽象データ型)から手をつけようとしていたようだ。 そこで、いま引っかかっているのは、型シグネチャの処理(adt-sample3) や、adt-sample4 は…なにかな。
これらの次に、deriving Show あたりをサポートしようとしていたらしい。
Sigdoc の処理にとりかかるにあたって、testcases を2つつくってみた。
sigdoc1.hs
main = putStrLn s where s :: [Char] s = "Hello, world!"
sigdoc2.hs
s :: String s = "Hello, world!" main = putStrLn s
2の方が(型シノニムの実装がいるので)難しいかと思ったら、こちらはすでに通ってしまった。 これは、現状の renSigdoc におけるハードコーディングのせいらしい。
-- TODO: should be fix this hard coding. renSigdoc (A.Tycon n) _ = case origName n of "Integer" -> return tInteger "Int" -> return tInt "String" -> return tString "IO" -> return $ TCon (Tycon "IO" (Kfun Star Star)) "()" -> return tUnit "Bool" -> return tBool s -> error $ "renSigDoc $ A.Tycon " ++ s
このあたりを、きちんと作っていくんだな。
わざと間違った型宣言をした sigdoc2err.hs はきちんと型エラーになったので、 すでに型宣言を型推論器にわたす経路はできている模様。
renSigdoc をハードコーディングのままだが "Char" -> tChar を追加して、とにかく "[Char]" を処理できるようにしてみた。 そこでの各テストケースの状況:
よくみる継続価値の式、簡単そうなんだけど自分で導出しようとしても、 同じにならないのでなんでかと思って調べたので、書き出しておいた: 継続価値式 (Cash Flow Perpetuity Formula)
自分でやって合わなかった理由は、 初年度のフリーキャッシュフローも、資本コストによって割り引かれるようにしてなかったから、だった。