forall とか 型クラスとか
勉強会(http://www.agusa.i.is.nagoya-u.ac.jp/person/mzp/hiki/?SICP)で、S 式ネイティブコンパイラを作ろうぜ、ということだったので、id:mzp や id:suer さんに手伝ってもらってちょっと作ってみてた。
前々から一度 forall を使ってみたかったのと、数値はひとつのデータコンストラクタで扱いたかったので、こんな感じに。Real とか Rational とかの関係がよくわからんくて無駄に時間がかかった。
{-# OPTIONS -fglasgow-exts #-} data LispNum = forall a. (Real a, Show a) => Number a instance Show LispNum where show (Number n) = show n instance Eq LispNum where (Number x) == (Number y) = toRational x == toRational y instance Num LispNum where (Number x) + (Number y) = Number . fromRational $ toRational x + toRational y
Main> Number 1 + Number 2 3.0 Main> Number 1 + Number 2.5 3.5 Main>
Number は、本来は
data LispVal = forall a. (Real a, Show a) => Number a | String String | Boolean Bool | ...
みたいに LispVal のうちのひとつとして使いたかったので、
data LispVal a = Number a ...
とかはやりたくなかった。いろいろ問題が発生して投げやりな感じに…。
というか、今思ったけどこれって全然ダメじゃね。単に Real な値を保持してるだけでは…。
んー?
data LispNum = LInt Int | LReal Rational instance Show LispNum where show (LInt i) = show i show (LReal r) = show $ fromRational r instance Eq LispNum where (LInt i) == (LInt j) = i==j (LReal r) == (LReal s) = r==s (LInt i) == (LReal r) = toRational i == toRational r (LReal r) == (LInt i) = toRational r == toRational i instance Num LispNum where (LInt i) + (LInt j ) = LInt $ i+j (LReal r) + (LReal s) = LReal $ r+s (LInt i) + (LReal r) = LReal $ toRational i + toRational r (LReal r) + (LInt i) = LReal $ toRational i + toRational r