如何在Haskell中处理表达式?

时间:2013-02-27 01:26:14

标签: haskell expression

让我说我有:

f :: Double -> Double
f x = 3*x^2 + 5*x + 9

我想计算这个函数的导数并写

derivate f

这样

derivate f == \x -> 6*x + 5

但如何定义derivate

derivate :: (a -> a) -> (a -> a)
derivate f = f' -- how to compute f'?

我知道没有本地方法可以做到这一点,但是有一个库可以吗?

我们是否必须依靠“meta”-datatypes来实现这一目标?

data Computation = Add Exp Expr | Mult Expr Expr | Power Expr Expr -- etc

那么,为每个函数创建相应的构造函数是不是很痛苦?但是,数据类型不应表示函数(解析器除外)。

由于其术语重写功能,Pure是一个不错的选择吗?它不也有缺点吗?

列表是否可以承受?

f :: [Double]
f = [3, 5, 9]

derivate :: (a -> [a])
derivate f = (*) <$> f <*> (getNs f)

compute f x = sum $
    ((*) . (^) x) <$> (getNs f) <*> f

getNs f = (reverse (iterate (length f) [0..]))

Haskell现在看起来依赖于LISP,语法不太合适。等待一起使用的函数和参数完全存储在数据类型中。 此外,它不是很自然。

除了多项式之外,它们似乎不够“灵活”,不能使用derivate函数,例如单应函数。

现在,例如,我想在游戏中使用衍生品。角色在使用功能的地板上运行,如果地板足够陡峭,我希望他能够滑动。

我还需要为各种目的求解方程。一些例子:

我是宇宙飞船,我想小睡一下。在我睡觉的时候,如果我没有小心翼翼地放置自己,我可能会因为引力而在地球上坠毁。我没有足够的气体远离天体,我也没有地图。 因此,我必须把自己置于这个区域内的物体之间,以便取消它们对我的重力影响的总和。 xy是我的坐标。 gravity是一个函数,它接收两个对象并在它们之间返回重力的向量。 如果有两个物体,比如地球和月球,除了我之外,我需要做的就是找到要去的地方:

gravity earth spaceship + gravity moon spaceship == (0, 0)

比从头equigravityPoint :: Object -> Object -> Object -> Point创建新功能更简单,更快捷等。

如果除了我之外还有3个物体,它仍然很简单。

gravity earth spaceship + gravity moon spaceship + gravity sun spaceship == (0, 0)

4和n相同。与equigravityPoint相比,处理对象列表要简单得多。

其他例子。 我想编写一个射击我的敌人机器人。 如果他只是针对我目前的位置射击,如果我向我跑去,他会得到我,但是如果我跳起来摔倒在他身上,他会想念我的。 一个更智能的机器人就是这样想的:“好吧,他从墙上跳下来。如果我射击目标他现在的子弹将不会得到他,因为他将移动到那时。所以我会预料到他会在哪里在几秒钟内拍摄,以便子弹和他同时到达这一点“。 基本上,我需要能够计算轨迹。例如,对于这种情况,我需要trajectoryBullet == trajectoryCharacter的解决方案,它给出了线和抛物线相遇的点。

一个不涉及速度的类似且更简单的例子。 我是一个消防员机器人,还有一座建筑物着火了。另一队消防员正在用水枪对抗火灾。我和有人跳了起来。当我的朋友们开水时,我拿着蹦床。 我需要去人们将要去的地方。所以我需要轨迹和方程求解。

2 个答案:

答案 0 :(得分:4)

数值导数可以很容易地完成:

derive f x = (f (x + dx) - f (x - dx)) / (2 * dx) where dx = 0.00001

但是,对于符号衍生物,您需要创建一个AST,然后通过匹配和重写AST来实现派生规则。

答案 1 :(得分:2)

我不明白您使用自定义数据类型的问题

data Expr = Plus Expr Expr 
           | Times Expr Expr 
           | Negate Expr 
           | Exp Expr Expr 
           | Abs Expr
           | Signum Expr
           | FromInteger Integer
           | Var

instance Num Expr where
   fromInteger = FromInteger
   (+) = Plus
   (*) = Times
   negate = Negate
   abs = Abs
   signum = Signum

toNumF :: Num a => Expr -> a -> a
toNumF e x = go e where
  go Var = x
  go (FromInteger i) = fromInteger i
  go (Plus a b) = (go a) + (go b)
  ...

然后你可以像IntDouble一样使用它,一切都会正常工作!您可以定义一个函数

deriveExpr :: Expr -> Expr

然后可以让你定义以下(RankN)函数

derivate :: Num b => (forall a. Num a => a -> a) -> b -> b
derivate f = toNumF $ deriveExpr (f Var)

您可以将其扩展为与数字层次结构的其他部分一起使用。