12

我宣布了一个关于应用函子的小组。从我们通常所说的“动作”来看,似乎这样的组可以使动作被撤消

import Control.Applicative

class Alternative f => Undoable f where
    undo :: f a -> f a

作为一个群体,对于所有人x :: Undoable f => f a,以下法律应满足:

x <|> undo x ≡ empty
undo x <|> x ≡ empty

一些实例:

import Control.Arrow
import Data.Functor.Compose
import Data.Functor.Product
import Data.Proxy

instance Undoable Proxy where
    undo _ = Proxy

instance (Undoable f, Applicative g) => Undoable (Compose f g) where
    undo (Compose x) = Compose (undo x)

instance (Undoable f, Undoable g) => Undoable (Product f g) where
    undo (Pair x y) = Pair (undo x) (undo y)

instance Undoable m => Undoable (Kleisli m a) where
    undo (Kleisli f) = Kleisli (undo . f)

至少对我来说,这些例子是没有意义的。一些非实例包括:

  • Maybe:一旦成功,无论其他选择如何,它总是会成功。

  • []and ZipList: 选项总是添加不确定性,而不是从中减去。

    • ReadPReadPrec:如上所述。
  • IO: 从字面上看,这个实例将是一台时间机器。即使我们可以取现实与时空的商,也有一个实际的反例:一个新的IORef不能被遗忘。

有什么特别有趣的例子Undoable吗?

4

2 回答 2

6

我会考虑这样的事情。不是Prelude.Functor因为密钥需要是可订购的(也可以是Hashable或仅是Eq,你知道权衡)。

它基本上是一个允许负多重性的多重集。反物质元素

import qualified Data.Map as Map
import qualified Prelude as Hask
import Data.List (sortOn)
import Control.Category.Constrained.Prelude
import Control.Arrow.Constrained
import Control.Applicative.Constrained

data Dirac n k = Dirac { getOccurences :: Map.Map k n }

instance Real n => Functor (Dirac n) (Ord⊢(->)) (->) where
  fmap (ConstrainedMorphism f) (Dirac m)
    = Dirac . Map.fromAscList
            . concatMap (\((k,n₀):grp) -> case sum $ n₀ : map snd grp of
                     0 -> []
                     μ -> [(k,μ)] )
            . groupBy (comparing fst)
            . sortOn fst
            . map (first f)
            $ Map.toList m

instance Num n => Undoable (Dirac n) where
  undo (Dirac m) = Dirac $ Map.map negate m

我认为可以围绕这个建立一个符合Applicative/Alternative建立的,但我不完全确定。

于 2021-10-08T08:52:53.317 回答
5

任何幺半群都可以提升到Alternative

newtype ViaMonoid m a = ViaMonoid m

instance Monoid m => Applicative (ViaMonoid m) where
    pure _ = ViaMonoid mempty
    ViaMonoid f <*> ViaMonoid x = ViaMonoid (f <> x)

instance Monoid m => Alternative (ViaMonoid m) where
    empty = ViaMonoid mempty
    ViaMonoid m <|> ViaMonoid m' = ViaMonoid (m <> m')

任何组都可以提升到Undo

class Monoid g => Group g where
    -- law: g <> inverse g = inverse g <> g = mempty
    inverse :: g -> g

instance Group g => Undoable (ViaMonoid g) where
    undo (ViaMonoid m) = ViaMonoid (inverse m)

ViaMonoid也以更传统的名称而闻名,并且在例如和朋友Const中用于良好的效果。lens

于 2021-10-08T15:34:58.477 回答