今更
大分前にHaskellで、多項式周りのアルゴリズムを色々実装して遊んでたけど、多項式型は、たぶん、誰でも考えるとおり
data Polynomial a = Const a | Var String | PLUS (Polynomial a) (Polynomial a) | MULT (Polynomial a) (Polynomial a) deriving (Show,Read) instance (Num a,Ord a) => Num (Polynomial a) where p+q = normalize(PLUS p q) p*q = normalize(MULT p q) p-q = normalize(PLUS p (MULT (Const (negate 1)) q) fromInteger n = Const (fromInteger n)
みたいな定義になってる。normalizeは、多項式を適当な標準形に直す関数。
で、がんばってパーサ書いたり、変数に値代入した時は〜とか色々やってたけど、Haskellって
Prelude> (\x y -> 2*x*x+y+3) (Var "x") (Var "y") PLUS (MULT (Const 2) (MULT (Var "x") (Var "x"))) (PLUS (Var "y") (const 3)) Prelude> (\x y -> 2*x*x+y+3) 4 (Var "hoge") PLUS (Var "hoge") (Const 35)
とかできてしまうんだよなぁって、気付いた。大したことじゃないけど、私は結構感動した。
逆もできるとよい。つまり、PLUS (MULT (Const 2) (MULT (Var "x") (Var "x"))) (PLUS (Var "y") (const 3))みたいな表現から、(\x y -> 2*x*x+y+3)みたいな式を得たい。式つくるだけなら、
--Language.Haskell.THをimportすること expandToHs :: Polynomial Integer -> Exp expandToHs p = LamE (map VarP $ vars p) (mkBody p) where vars(Const _) = [] vars(Var x) = [mkName x] vars(PLUS p q) = nub $ (vars p)++(vars q) vars(MULT p q) = nub $ (vars p)++(vars q) mkBody (Const n) = (LitE (IntegerL n)) mkBody (Var v) = (VarE (mkName v)) mkBody (PLUS p q) = InfixE (Just (mkBody p)) (VarE (mkName "+")) (Just (mkBody q)) mkBody (MULT p q) = InfixE (Just (mkBody p)) (VarE (mkName "*")) (Just (mkBody q))
とかでしまい
Prelude> ppr $ expandToHs ((\x y ->2*x*x*x+y*3) (Var "a") (Var "b")) \a b -> (2 * (a * (a * a))) + (3 * b)