dy/dx
Submitted by Greg Buchholz on Thu, 10/20/2005 - 2:23pm.
Over on comp.lang.lisp we have someone trying to use Haskell for a little symbolic differentiation problem. Since it doesn't even compile, I thought I'd throw my hat in the ring and clean it up a little (Is there a better way to display snippets on this site? I had to use <pre> tags instead of <code> tags)...
infixl 5 :+
infixl 6 :*
data Exp = Num Integer
| Var Sym
| Exp :+ Exp
| Exp :* Exp deriving (Eq,Show)
data Sym = X | Y deriving (Eq,Show)
main = do let exp = (Num 4 :* Var X :* Var X)
let deriv = d exp X
putStrLn $ "Original expression : " ++ (show exp)
putStrLn $ "Derivative : " ++ (show $ simplify deriv)
putStrLn $ "Derivative evaluated at X=10 : "
++ (show $ eval (d exp X) [(X,10)])
--take the derivative...
d (Num n) x = Num 0
d (Var y) x | x==y = Num 1
| otherwise = Num 0
d (f :+ g) x = (d f x) :+ (d g x)
d (f :* g) x = (d f x) :* g :+ f :* (d g x)
--evaluate an Exp...
eval (Num x) env = x
eval (Var x) env = case (lookup x env) of
(Just n) -> n
(Nothing) -> error $ "no variable "++(show x)++" in env"
eval (x :+ y) env = eval x env + eval y env
eval (x :* y) env = eval x env * eval y env
--a few algebraic simplification rules
simp (x :+ y) | x == y = simp (Num 2):*x
simp ((Num 0) :+ x) = simp x
simp (x :+ (Num 0)) = simp x
simp ((Num x) :+ (Num y)) = Num (x+y)
simp (x :+ y) = simp x :+ simp y
simp ((Num 0) :* x) = Num 0
simp (x :* (Num 0)) = Num 0
simp ((Num 1) :* x) = simp x
simp (x :* (Num 1)) = simp x
simp ((Num x) :* (Num y)) = Num (x*y)
simp (x :* y) = simp x :* simp y
simp x = x
--apply simplification rules until the expression doesn't change anymore
simplify x = let a = iterate simp x
fix = dropWhile (\(c,d)->c/=d) $ zip a (tail a)
in (fst.head) fix
- Greg Buchholz's blog
- Login to post comments