我在Haskell中有以下代码:
move :: Camera -> (Double, Double, Double) -> Camera
move camera (xt, yt, zt) = camera { cPosition = (x + xt, y + yt, z + zt) }
where (x, y, z) = cPosition camera
moveForward :: Camera -> Camera
moveForward camera = move camera (-1 * sin ya, 0, -1 * cos ya)
where (_, ya, _) = cRotation camera
moveBackward :: Camera -> Camera
moveBackward camera = move camera (sin ya, 0, cos ya)
where (_, ya, _) = cRotation camera
您会注意到moveForward
和moveBackward
函数具有相同的where
语句。有没有办法删除这种重复?我有许多具有相同where
子句的函数(读取:超过两个)。
我宁愿不把它作为另一个论点传递 - 因为它永远不会改变。它始终是cRotation
。
答案 0 :(得分:7)
如何使这些函数将元组作为参数,然后用另一个自动执行提取元组的无聊工作的函数包装它们?
rotated :: ((Double, Double, Double) -> Camera -> a) -> Camera -> a
rotated f camera = f (cPosition camera) camera
moveForward :: Camera -> Camera
moveForward = rotated moveForward'
where moveForward' (_, ya, _) camera = move camera (-1 * sin ya, 0, -1 * cos ya)
moveBackward :: Camera -> Camera
moveBackward = rotated moveBackward'
where moveBackward' (_, ya, _) camera = move camera (sin ya, 0, cos ya)
编辑:六个月后查看我的答案,我注意到可以解除更多重复:move camera
电话。所以像moveForward
这样的函数真的可以采用3元组并返回3元组,如下所示:
moveRotated :: ((Double, Double, Double) -> (Double, Double, Double)) -> Camera -> Camera
moveRotated f camera = move camera . f $ cPosition camera
moveForward :: Camera -> Camera
moveForward = moveRotated forward
where forward (_, ya, _) = (- sin ya, 0, - cos ya)
moveBackward :: Camera -> Camera
moveBackward = moveRotated backward
where backward (_, ya, _) = (sin ya, 0, cos ya)
这给moveForward
和moveBackward
提供了更少的权力,当然,因为除了移动之外你不能用它们做任何事情。但它很好地将它们提炼到它们的本质,并确保你不会意外地做一些其他事情而不是移动。
答案 1 :(得分:2)
只需定义自己的功能就可以得到简单的答案
snd3 :: (a, b, c) -> b
snd3 (a, b, c) = b
然后你可以使用lambda
moveForward camera = \ya -> (-1 * sin ya, 0, -1 * cos ya) $ snd3 $ cRotation camera
moveBackward camera = \ya -> (sin ya, 0, cos ya) $ snd3 $ cRotation camera
或者,如果您要将lens
库添加为依赖项,则可以将snd3 cRotation camera
替换为cRotation camera ^. _2
或等效view _2 $ cRotation camera
。至于删除lambda,除了定义一个新函数
apply3 :: (a -> a') -> (b -> b') -> (c -> c') -> (a, b, c) -> (a', b', c')
apply3 f1 f2 f3 (a, b, c) = (f1 a, f2 b, f3 c)
moveForward = apply3 (negate . sin) (const 0) (negate . cos) . snd3 . cRotation
moveBackward = apply3 sin (const 0) cos . snd3 . cRotation
并使用一些eta减少。
不幸的是,使用2元组有很多优雅的技巧,但3元组没有那么多。