将自同态转化为应用性

问题描述 投票:0回答:1

假设我们有一个具有明显操作的

data Vector
(所以 Vector 是 Monoid 的实例)

(+):: Vector -> Vector -> Vector

现在,假设我们希望某个对象可以通过矢量移动。 假设我确切地知道哪些类型被认为是可移动的,所以一些移动功能

move :: Vector -> Movable -> Movable

哪里

data Movable = Movable t1 | t2 | t3

或者课堂版

class Movable a where
  move :: Vector -> a -> a

使用表格的一些实例

instance Movable ti where
  move :: Vector -> ti -> ti

就我个人而言,我更喜欢课堂版。

现在,假设我们有一系列计算大致相当于

move v1 . move v2 . move v3

最终相当于

move (v1 + v2 + v3)

我们想要优化:

move (v1 + v2)
move v1 . move v2
便宜得多。

问题:据我所知,这就是 Applicative 派上用场的地方? 如何在正确的 Haskell 中实现它?

我想出了以下方法:将信息存储在表单的某个容器中

data Move a = Move {data :: a, offset :: Vector}

并且有独立的功能

transform :: Movable a => Move a -> a

这样我们就可以实现了

instance Applicative (Move a)

但我觉得很难看。有没有更好的办法? 能不能转成Monad(只是为了使用灵活的标准库)

UPD:我需要的是: 如果我有一个可移动对象

x
,并且我变换它

y = move v1 $ move v2 $ move v3 $ x

Haskell 必须在内部将其变成

y = move (v1 + v2 + v3) x

仅当我评估时

y

haskell coordinate-transformation applicative monoids
1个回答
0
投票

我想懒惰会有所帮助。

data Moved a = Moved { base :: a, result :: a, offset :: Vector }

-- smart constructor; not really needed, strictly speaking
moved :: Movable a => a -> Vector -> Moved a
moved b o = Moved b (move b o) o

instance Movable a => Movable (Moved a) where
    move v m = moved (base m) (v + offset m)

第一次访问

result
对象的
Moved
时,将会对其进行计算(但进一步的访问将使用之前计算的结果)。中间
result
将被丢弃,而不会产生其
move
的成本。

© www.soinside.com 2019 - 2024. All rights reserved.