为什么这个类型 class 实例无法统一?

Why is this type class instance failed to unify?

我正在尝试用 PureScript 编写类似 Redux 的商店。

我为每个动作定义了 Action 类型 class 和代数数据类型以划分为更小的模块。

class Action a

data FooAction
  = UpdateFoo String
  | ResetFoo

data BarAction
  = UpdateBar Int
  | ResetBar

data ResetAll = ResetAll

instance fooAction :: Action FooAction    
instance barAction :: Action BarAction

并定义了一些状态类型和更新函数。更新功能可能会收到所有类型的操作。

newtype Foo = Foo String
newtype Bar = Bar Int

updateFoo :: forall a. (Action a) => a -> Foo -> Foo
updateFoo a foo =
  case a of
    UpdateFoo str -> Foo str
    ResetFoo      -> Foo ""
    ResetAll      -> Foo ""
    _             -> foo

updateBar :: forall a. (Action a) => a -> Bar -> Bar
updateBar a bar =
  case a of
    UpdateBar num -> Bar num
    ResetBar      -> Bar 0
    ResetAll      -> Bar 0
    _             -> bar

但是此代码会产生 TypesDoNotUnify 错误。

  Could not match type

    FooAction

  with type

    a0


while checking that expression case a of
                                 (UpdateFoo str) -> Foo str
                                 ResetFoo -> Foo ""
                                 ResetAll -> Foo ""
                                 _ -> foo
  has type Foo
in value declaration updateFoo

where a0 is a rigid type variable

为什么会出现这个错误?我应该如何实现这样的更新功能?

这里的问题是您在匹配值 Action a => a 时就好像它是 Foo,因此会出现类型错误。

如果您想使用 classes 来解决问题,方法是将操作作为 class 的一部分,而不是不同类型的数据构造函数:

class Thing a
  update :: a -> String
  reset :: a -> Unit

然后你可以调用 updateresetFoo , Bar, Baz 或你实现 Thing实例。

如果问题是您想表示这些东西可以执行的不同操作集,那么您也可以使用子class:

class Thing a <= SubThing a
  act :: a -> Unit

虽然我不确定我是否完全理解您在这里尝试做的事情,所以也许这并不是您真正想要的,但希望能给您一些想法。